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.
Files changed (314) hide show
  1. agno/agent/agent.py +6015 -2823
  2. agno/api/api.py +2 -0
  3. agno/api/os.py +1 -1
  4. agno/culture/__init__.py +3 -0
  5. agno/culture/manager.py +956 -0
  6. agno/db/async_postgres/__init__.py +3 -0
  7. agno/db/base.py +385 -6
  8. agno/db/dynamo/dynamo.py +388 -81
  9. agno/db/dynamo/schemas.py +47 -10
  10. agno/db/dynamo/utils.py +63 -4
  11. agno/db/firestore/firestore.py +435 -64
  12. agno/db/firestore/schemas.py +11 -0
  13. agno/db/firestore/utils.py +102 -4
  14. agno/db/gcs_json/gcs_json_db.py +384 -42
  15. agno/db/gcs_json/utils.py +60 -26
  16. agno/db/in_memory/in_memory_db.py +351 -66
  17. agno/db/in_memory/utils.py +60 -2
  18. agno/db/json/json_db.py +339 -48
  19. agno/db/json/utils.py +60 -26
  20. agno/db/migrations/manager.py +199 -0
  21. agno/db/migrations/v1_to_v2.py +510 -37
  22. agno/db/migrations/versions/__init__.py +0 -0
  23. agno/db/migrations/versions/v2_3_0.py +938 -0
  24. agno/db/mongo/__init__.py +15 -1
  25. agno/db/mongo/async_mongo.py +2036 -0
  26. agno/db/mongo/mongo.py +653 -76
  27. agno/db/mongo/schemas.py +13 -0
  28. agno/db/mongo/utils.py +80 -8
  29. agno/db/mysql/mysql.py +687 -25
  30. agno/db/mysql/schemas.py +61 -37
  31. agno/db/mysql/utils.py +60 -2
  32. agno/db/postgres/__init__.py +2 -1
  33. agno/db/postgres/async_postgres.py +2001 -0
  34. agno/db/postgres/postgres.py +676 -57
  35. agno/db/postgres/schemas.py +43 -18
  36. agno/db/postgres/utils.py +164 -2
  37. agno/db/redis/redis.py +344 -38
  38. agno/db/redis/schemas.py +18 -0
  39. agno/db/redis/utils.py +60 -2
  40. agno/db/schemas/__init__.py +2 -1
  41. agno/db/schemas/culture.py +120 -0
  42. agno/db/schemas/memory.py +13 -0
  43. agno/db/singlestore/schemas.py +26 -1
  44. agno/db/singlestore/singlestore.py +687 -53
  45. agno/db/singlestore/utils.py +60 -2
  46. agno/db/sqlite/__init__.py +2 -1
  47. agno/db/sqlite/async_sqlite.py +2371 -0
  48. agno/db/sqlite/schemas.py +24 -0
  49. agno/db/sqlite/sqlite.py +774 -85
  50. agno/db/sqlite/utils.py +168 -5
  51. agno/db/surrealdb/__init__.py +3 -0
  52. agno/db/surrealdb/metrics.py +292 -0
  53. agno/db/surrealdb/models.py +309 -0
  54. agno/db/surrealdb/queries.py +71 -0
  55. agno/db/surrealdb/surrealdb.py +1361 -0
  56. agno/db/surrealdb/utils.py +147 -0
  57. agno/db/utils.py +50 -22
  58. agno/eval/accuracy.py +50 -43
  59. agno/eval/performance.py +6 -3
  60. agno/eval/reliability.py +6 -3
  61. agno/eval/utils.py +33 -16
  62. agno/exceptions.py +68 -1
  63. agno/filters.py +354 -0
  64. agno/guardrails/__init__.py +6 -0
  65. agno/guardrails/base.py +19 -0
  66. agno/guardrails/openai.py +144 -0
  67. agno/guardrails/pii.py +94 -0
  68. agno/guardrails/prompt_injection.py +52 -0
  69. agno/integrations/discord/client.py +1 -0
  70. agno/knowledge/chunking/agentic.py +13 -10
  71. agno/knowledge/chunking/fixed.py +1 -1
  72. agno/knowledge/chunking/semantic.py +40 -8
  73. agno/knowledge/chunking/strategy.py +59 -15
  74. agno/knowledge/embedder/aws_bedrock.py +9 -4
  75. agno/knowledge/embedder/azure_openai.py +54 -0
  76. agno/knowledge/embedder/base.py +2 -0
  77. agno/knowledge/embedder/cohere.py +184 -5
  78. agno/knowledge/embedder/fastembed.py +1 -1
  79. agno/knowledge/embedder/google.py +79 -1
  80. agno/knowledge/embedder/huggingface.py +9 -4
  81. agno/knowledge/embedder/jina.py +63 -0
  82. agno/knowledge/embedder/mistral.py +78 -11
  83. agno/knowledge/embedder/nebius.py +1 -1
  84. agno/knowledge/embedder/ollama.py +13 -0
  85. agno/knowledge/embedder/openai.py +37 -65
  86. agno/knowledge/embedder/sentence_transformer.py +8 -4
  87. agno/knowledge/embedder/vllm.py +262 -0
  88. agno/knowledge/embedder/voyageai.py +69 -16
  89. agno/knowledge/knowledge.py +594 -186
  90. agno/knowledge/reader/base.py +9 -2
  91. agno/knowledge/reader/csv_reader.py +8 -10
  92. agno/knowledge/reader/docx_reader.py +5 -6
  93. agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
  94. agno/knowledge/reader/json_reader.py +6 -5
  95. agno/knowledge/reader/markdown_reader.py +13 -13
  96. agno/knowledge/reader/pdf_reader.py +43 -68
  97. agno/knowledge/reader/pptx_reader.py +101 -0
  98. agno/knowledge/reader/reader_factory.py +51 -6
  99. agno/knowledge/reader/s3_reader.py +3 -15
  100. agno/knowledge/reader/tavily_reader.py +194 -0
  101. agno/knowledge/reader/text_reader.py +13 -13
  102. agno/knowledge/reader/web_search_reader.py +2 -43
  103. agno/knowledge/reader/website_reader.py +43 -25
  104. agno/knowledge/reranker/__init__.py +2 -8
  105. agno/knowledge/types.py +9 -0
  106. agno/knowledge/utils.py +20 -0
  107. agno/media.py +72 -0
  108. agno/memory/manager.py +336 -82
  109. agno/models/aimlapi/aimlapi.py +2 -2
  110. agno/models/anthropic/claude.py +183 -37
  111. agno/models/aws/bedrock.py +52 -112
  112. agno/models/aws/claude.py +33 -1
  113. agno/models/azure/ai_foundry.py +33 -15
  114. agno/models/azure/openai_chat.py +25 -8
  115. agno/models/base.py +999 -519
  116. agno/models/cerebras/cerebras.py +19 -13
  117. agno/models/cerebras/cerebras_openai.py +8 -5
  118. agno/models/cohere/chat.py +27 -1
  119. agno/models/cometapi/__init__.py +5 -0
  120. agno/models/cometapi/cometapi.py +57 -0
  121. agno/models/dashscope/dashscope.py +1 -0
  122. agno/models/deepinfra/deepinfra.py +2 -2
  123. agno/models/deepseek/deepseek.py +2 -2
  124. agno/models/fireworks/fireworks.py +2 -2
  125. agno/models/google/gemini.py +103 -31
  126. agno/models/groq/groq.py +28 -11
  127. agno/models/huggingface/huggingface.py +2 -1
  128. agno/models/internlm/internlm.py +2 -2
  129. agno/models/langdb/langdb.py +4 -4
  130. agno/models/litellm/chat.py +18 -1
  131. agno/models/litellm/litellm_openai.py +2 -2
  132. agno/models/llama_cpp/__init__.py +5 -0
  133. agno/models/llama_cpp/llama_cpp.py +22 -0
  134. agno/models/message.py +139 -0
  135. agno/models/meta/llama.py +27 -10
  136. agno/models/meta/llama_openai.py +5 -17
  137. agno/models/nebius/nebius.py +6 -6
  138. agno/models/nexus/__init__.py +3 -0
  139. agno/models/nexus/nexus.py +22 -0
  140. agno/models/nvidia/nvidia.py +2 -2
  141. agno/models/ollama/chat.py +59 -5
  142. agno/models/openai/chat.py +69 -29
  143. agno/models/openai/responses.py +103 -106
  144. agno/models/openrouter/openrouter.py +41 -3
  145. agno/models/perplexity/perplexity.py +4 -5
  146. agno/models/portkey/portkey.py +3 -3
  147. agno/models/requesty/__init__.py +5 -0
  148. agno/models/requesty/requesty.py +52 -0
  149. agno/models/response.py +77 -1
  150. agno/models/sambanova/sambanova.py +2 -2
  151. agno/models/siliconflow/__init__.py +5 -0
  152. agno/models/siliconflow/siliconflow.py +25 -0
  153. agno/models/together/together.py +2 -2
  154. agno/models/utils.py +254 -8
  155. agno/models/vercel/v0.py +2 -2
  156. agno/models/vertexai/__init__.py +0 -0
  157. agno/models/vertexai/claude.py +96 -0
  158. agno/models/vllm/vllm.py +1 -0
  159. agno/models/xai/xai.py +3 -2
  160. agno/os/app.py +543 -178
  161. agno/os/auth.py +24 -14
  162. agno/os/config.py +1 -0
  163. agno/os/interfaces/__init__.py +1 -0
  164. agno/os/interfaces/a2a/__init__.py +3 -0
  165. agno/os/interfaces/a2a/a2a.py +42 -0
  166. agno/os/interfaces/a2a/router.py +250 -0
  167. agno/os/interfaces/a2a/utils.py +924 -0
  168. agno/os/interfaces/agui/agui.py +23 -7
  169. agno/os/interfaces/agui/router.py +27 -3
  170. agno/os/interfaces/agui/utils.py +242 -142
  171. agno/os/interfaces/base.py +6 -2
  172. agno/os/interfaces/slack/router.py +81 -23
  173. agno/os/interfaces/slack/slack.py +29 -14
  174. agno/os/interfaces/whatsapp/router.py +11 -4
  175. agno/os/interfaces/whatsapp/whatsapp.py +14 -7
  176. agno/os/mcp.py +111 -54
  177. agno/os/middleware/__init__.py +7 -0
  178. agno/os/middleware/jwt.py +233 -0
  179. agno/os/router.py +556 -139
  180. agno/os/routers/evals/evals.py +71 -34
  181. agno/os/routers/evals/schemas.py +31 -31
  182. agno/os/routers/evals/utils.py +6 -5
  183. agno/os/routers/health.py +31 -0
  184. agno/os/routers/home.py +52 -0
  185. agno/os/routers/knowledge/knowledge.py +185 -38
  186. agno/os/routers/knowledge/schemas.py +82 -22
  187. agno/os/routers/memory/memory.py +158 -53
  188. agno/os/routers/memory/schemas.py +20 -16
  189. agno/os/routers/metrics/metrics.py +20 -8
  190. agno/os/routers/metrics/schemas.py +16 -16
  191. agno/os/routers/session/session.py +499 -38
  192. agno/os/schema.py +308 -198
  193. agno/os/utils.py +401 -41
  194. agno/reasoning/anthropic.py +80 -0
  195. agno/reasoning/azure_ai_foundry.py +2 -2
  196. agno/reasoning/deepseek.py +2 -2
  197. agno/reasoning/default.py +3 -1
  198. agno/reasoning/gemini.py +73 -0
  199. agno/reasoning/groq.py +2 -2
  200. agno/reasoning/ollama.py +2 -2
  201. agno/reasoning/openai.py +7 -2
  202. agno/reasoning/vertexai.py +76 -0
  203. agno/run/__init__.py +6 -0
  204. agno/run/agent.py +248 -94
  205. agno/run/base.py +44 -5
  206. agno/run/team.py +238 -97
  207. agno/run/workflow.py +144 -33
  208. agno/session/agent.py +105 -89
  209. agno/session/summary.py +65 -25
  210. agno/session/team.py +176 -96
  211. agno/session/workflow.py +406 -40
  212. agno/team/team.py +3854 -1610
  213. agno/tools/dalle.py +2 -4
  214. agno/tools/decorator.py +4 -2
  215. agno/tools/duckduckgo.py +15 -11
  216. agno/tools/e2b.py +14 -7
  217. agno/tools/eleven_labs.py +23 -25
  218. agno/tools/exa.py +21 -16
  219. agno/tools/file.py +153 -23
  220. agno/tools/file_generation.py +350 -0
  221. agno/tools/firecrawl.py +4 -4
  222. agno/tools/function.py +250 -30
  223. agno/tools/gmail.py +238 -14
  224. agno/tools/google_drive.py +270 -0
  225. agno/tools/googlecalendar.py +36 -8
  226. agno/tools/googlesheets.py +20 -5
  227. agno/tools/jira.py +20 -0
  228. agno/tools/knowledge.py +3 -3
  229. agno/tools/mcp/__init__.py +10 -0
  230. agno/tools/mcp/mcp.py +331 -0
  231. agno/tools/mcp/multi_mcp.py +347 -0
  232. agno/tools/mcp/params.py +24 -0
  233. agno/tools/mcp_toolbox.py +284 -0
  234. agno/tools/mem0.py +11 -17
  235. agno/tools/memori.py +1 -53
  236. agno/tools/memory.py +419 -0
  237. agno/tools/models/nebius.py +5 -5
  238. agno/tools/models_labs.py +20 -10
  239. agno/tools/notion.py +204 -0
  240. agno/tools/parallel.py +314 -0
  241. agno/tools/scrapegraph.py +58 -31
  242. agno/tools/searxng.py +2 -2
  243. agno/tools/serper.py +2 -2
  244. agno/tools/slack.py +18 -3
  245. agno/tools/spider.py +2 -2
  246. agno/tools/tavily.py +146 -0
  247. agno/tools/whatsapp.py +1 -1
  248. agno/tools/workflow.py +278 -0
  249. agno/tools/yfinance.py +12 -11
  250. agno/utils/agent.py +820 -0
  251. agno/utils/audio.py +27 -0
  252. agno/utils/common.py +90 -1
  253. agno/utils/events.py +217 -2
  254. agno/utils/gemini.py +180 -22
  255. agno/utils/hooks.py +57 -0
  256. agno/utils/http.py +111 -0
  257. agno/utils/knowledge.py +12 -5
  258. agno/utils/log.py +1 -0
  259. agno/utils/mcp.py +92 -2
  260. agno/utils/media.py +188 -10
  261. agno/utils/merge_dict.py +22 -1
  262. agno/utils/message.py +60 -0
  263. agno/utils/models/claude.py +40 -11
  264. agno/utils/print_response/agent.py +105 -21
  265. agno/utils/print_response/team.py +103 -38
  266. agno/utils/print_response/workflow.py +251 -34
  267. agno/utils/reasoning.py +22 -1
  268. agno/utils/serialize.py +32 -0
  269. agno/utils/streamlit.py +16 -10
  270. agno/utils/string.py +41 -0
  271. agno/utils/team.py +98 -9
  272. agno/utils/tools.py +1 -1
  273. agno/vectordb/base.py +23 -4
  274. agno/vectordb/cassandra/cassandra.py +65 -9
  275. agno/vectordb/chroma/chromadb.py +182 -38
  276. agno/vectordb/clickhouse/clickhousedb.py +64 -11
  277. agno/vectordb/couchbase/couchbase.py +105 -10
  278. agno/vectordb/lancedb/lance_db.py +124 -133
  279. agno/vectordb/langchaindb/langchaindb.py +25 -7
  280. agno/vectordb/lightrag/lightrag.py +17 -3
  281. agno/vectordb/llamaindex/__init__.py +3 -0
  282. agno/vectordb/llamaindex/llamaindexdb.py +46 -7
  283. agno/vectordb/milvus/milvus.py +126 -9
  284. agno/vectordb/mongodb/__init__.py +7 -1
  285. agno/vectordb/mongodb/mongodb.py +112 -7
  286. agno/vectordb/pgvector/pgvector.py +142 -21
  287. agno/vectordb/pineconedb/pineconedb.py +80 -8
  288. agno/vectordb/qdrant/qdrant.py +125 -39
  289. agno/vectordb/redis/__init__.py +9 -0
  290. agno/vectordb/redis/redisdb.py +694 -0
  291. agno/vectordb/singlestore/singlestore.py +111 -25
  292. agno/vectordb/surrealdb/surrealdb.py +31 -5
  293. agno/vectordb/upstashdb/upstashdb.py +76 -8
  294. agno/vectordb/weaviate/weaviate.py +86 -15
  295. agno/workflow/__init__.py +2 -0
  296. agno/workflow/agent.py +299 -0
  297. agno/workflow/condition.py +112 -18
  298. agno/workflow/loop.py +69 -10
  299. agno/workflow/parallel.py +266 -118
  300. agno/workflow/router.py +110 -17
  301. agno/workflow/step.py +638 -129
  302. agno/workflow/steps.py +65 -6
  303. agno/workflow/types.py +61 -23
  304. agno/workflow/workflow.py +2085 -272
  305. {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/METADATA +182 -58
  306. agno-2.3.0.dist-info/RECORD +577 -0
  307. agno/knowledge/reader/url_reader.py +0 -128
  308. agno/tools/googlesearch.py +0 -98
  309. agno/tools/mcp.py +0 -610
  310. agno/utils/models/aws_claude.py +0 -170
  311. agno-2.0.1.dist-info/RECORD +0 -515
  312. {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/WHEEL +0 -0
  313. {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/licenses/LICENSE +0 -0
  314. {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/top_level.txt +0 -0
@@ -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
 
@@ -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
- id: str = "claude-3-5-sonnet-20241022"
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] = 4096
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.mcp_servers is not None:
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
- **self.get_request_params(),
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
- if self.mcp_servers is not None:
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
- if self.mcp_servers is not None:
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
- **self.get_request_params(),
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.mcp_servers is not None:
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 {}