agno 2.2.13__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/__init__.py +8 -0
- agno/agent/__init__.py +51 -0
- agno/agent/agent.py +10405 -0
- agno/api/__init__.py +0 -0
- agno/api/agent.py +28 -0
- agno/api/api.py +40 -0
- agno/api/evals.py +22 -0
- agno/api/os.py +17 -0
- agno/api/routes.py +13 -0
- agno/api/schemas/__init__.py +9 -0
- agno/api/schemas/agent.py +16 -0
- agno/api/schemas/evals.py +16 -0
- agno/api/schemas/os.py +14 -0
- agno/api/schemas/response.py +6 -0
- agno/api/schemas/team.py +16 -0
- agno/api/schemas/utils.py +21 -0
- agno/api/schemas/workflows.py +16 -0
- agno/api/settings.py +53 -0
- agno/api/team.py +30 -0
- agno/api/workflow.py +28 -0
- agno/cloud/aws/base.py +214 -0
- agno/cloud/aws/s3/__init__.py +2 -0
- agno/cloud/aws/s3/api_client.py +43 -0
- agno/cloud/aws/s3/bucket.py +195 -0
- agno/cloud/aws/s3/object.py +57 -0
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/__init__.py +24 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +598 -0
- agno/db/dynamo/__init__.py +3 -0
- agno/db/dynamo/dynamo.py +2042 -0
- agno/db/dynamo/schemas.py +314 -0
- agno/db/dynamo/utils.py +743 -0
- agno/db/firestore/__init__.py +3 -0
- agno/db/firestore/firestore.py +1795 -0
- agno/db/firestore/schemas.py +140 -0
- agno/db/firestore/utils.py +376 -0
- agno/db/gcs_json/__init__.py +3 -0
- agno/db/gcs_json/gcs_json_db.py +1335 -0
- agno/db/gcs_json/utils.py +228 -0
- agno/db/in_memory/__init__.py +3 -0
- agno/db/in_memory/in_memory_db.py +1160 -0
- agno/db/in_memory/utils.py +230 -0
- agno/db/json/__init__.py +3 -0
- agno/db/json/json_db.py +1328 -0
- agno/db/json/utils.py +230 -0
- agno/db/migrations/__init__.py +0 -0
- agno/db/migrations/v1_to_v2.py +635 -0
- agno/db/mongo/__init__.py +17 -0
- agno/db/mongo/async_mongo.py +2026 -0
- agno/db/mongo/mongo.py +1982 -0
- agno/db/mongo/schemas.py +87 -0
- agno/db/mongo/utils.py +259 -0
- agno/db/mysql/__init__.py +3 -0
- agno/db/mysql/mysql.py +2308 -0
- agno/db/mysql/schemas.py +138 -0
- agno/db/mysql/utils.py +355 -0
- agno/db/postgres/__init__.py +4 -0
- agno/db/postgres/async_postgres.py +1927 -0
- agno/db/postgres/postgres.py +2260 -0
- agno/db/postgres/schemas.py +139 -0
- agno/db/postgres/utils.py +442 -0
- agno/db/redis/__init__.py +3 -0
- agno/db/redis/redis.py +1660 -0
- agno/db/redis/schemas.py +123 -0
- agno/db/redis/utils.py +346 -0
- agno/db/schemas/__init__.py +4 -0
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/evals.py +33 -0
- agno/db/schemas/knowledge.py +40 -0
- agno/db/schemas/memory.py +46 -0
- agno/db/schemas/metrics.py +0 -0
- agno/db/singlestore/__init__.py +3 -0
- agno/db/singlestore/schemas.py +130 -0
- agno/db/singlestore/singlestore.py +2272 -0
- agno/db/singlestore/utils.py +384 -0
- agno/db/sqlite/__init__.py +4 -0
- agno/db/sqlite/async_sqlite.py +2293 -0
- agno/db/sqlite/schemas.py +133 -0
- agno/db/sqlite/sqlite.py +2288 -0
- agno/db/sqlite/utils.py +431 -0
- 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 +1353 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +116 -0
- agno/debug.py +18 -0
- agno/eval/__init__.py +14 -0
- agno/eval/accuracy.py +834 -0
- agno/eval/performance.py +773 -0
- agno/eval/reliability.py +306 -0
- agno/eval/utils.py +119 -0
- agno/exceptions.py +161 -0
- 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/__init__.py +0 -0
- agno/integrations/discord/__init__.py +3 -0
- agno/integrations/discord/client.py +203 -0
- agno/knowledge/__init__.py +5 -0
- agno/knowledge/chunking/__init__.py +0 -0
- agno/knowledge/chunking/agentic.py +79 -0
- agno/knowledge/chunking/document.py +91 -0
- agno/knowledge/chunking/fixed.py +57 -0
- agno/knowledge/chunking/markdown.py +151 -0
- agno/knowledge/chunking/recursive.py +63 -0
- agno/knowledge/chunking/row.py +39 -0
- agno/knowledge/chunking/semantic.py +86 -0
- agno/knowledge/chunking/strategy.py +165 -0
- agno/knowledge/content.py +74 -0
- agno/knowledge/document/__init__.py +5 -0
- agno/knowledge/document/base.py +58 -0
- agno/knowledge/embedder/__init__.py +5 -0
- agno/knowledge/embedder/aws_bedrock.py +343 -0
- agno/knowledge/embedder/azure_openai.py +210 -0
- agno/knowledge/embedder/base.py +23 -0
- agno/knowledge/embedder/cohere.py +323 -0
- agno/knowledge/embedder/fastembed.py +62 -0
- agno/knowledge/embedder/fireworks.py +13 -0
- agno/knowledge/embedder/google.py +258 -0
- agno/knowledge/embedder/huggingface.py +94 -0
- agno/knowledge/embedder/jina.py +182 -0
- agno/knowledge/embedder/langdb.py +22 -0
- agno/knowledge/embedder/mistral.py +206 -0
- agno/knowledge/embedder/nebius.py +13 -0
- agno/knowledge/embedder/ollama.py +154 -0
- agno/knowledge/embedder/openai.py +195 -0
- agno/knowledge/embedder/sentence_transformer.py +63 -0
- agno/knowledge/embedder/together.py +13 -0
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +165 -0
- agno/knowledge/knowledge.py +1988 -0
- agno/knowledge/reader/__init__.py +7 -0
- agno/knowledge/reader/arxiv_reader.py +81 -0
- agno/knowledge/reader/base.py +95 -0
- agno/knowledge/reader/csv_reader.py +166 -0
- agno/knowledge/reader/docx_reader.py +82 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +292 -0
- agno/knowledge/reader/firecrawl_reader.py +201 -0
- agno/knowledge/reader/json_reader.py +87 -0
- agno/knowledge/reader/markdown_reader.py +137 -0
- agno/knowledge/reader/pdf_reader.py +431 -0
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +313 -0
- agno/knowledge/reader/s3_reader.py +89 -0
- agno/knowledge/reader/tavily_reader.py +194 -0
- agno/knowledge/reader/text_reader.py +115 -0
- agno/knowledge/reader/web_search_reader.py +372 -0
- agno/knowledge/reader/website_reader.py +455 -0
- agno/knowledge/reader/wikipedia_reader.py +59 -0
- agno/knowledge/reader/youtube_reader.py +78 -0
- agno/knowledge/remote_content/__init__.py +0 -0
- agno/knowledge/remote_content/remote_content.py +88 -0
- agno/knowledge/reranker/__init__.py +3 -0
- agno/knowledge/reranker/base.py +14 -0
- agno/knowledge/reranker/cohere.py +64 -0
- agno/knowledge/reranker/infinity.py +195 -0
- agno/knowledge/reranker/sentence_transformer.py +54 -0
- agno/knowledge/types.py +39 -0
- agno/knowledge/utils.py +189 -0
- agno/media.py +462 -0
- agno/memory/__init__.py +3 -0
- agno/memory/manager.py +1327 -0
- agno/models/__init__.py +0 -0
- agno/models/aimlapi/__init__.py +5 -0
- agno/models/aimlapi/aimlapi.py +45 -0
- agno/models/anthropic/__init__.py +5 -0
- agno/models/anthropic/claude.py +757 -0
- agno/models/aws/__init__.py +15 -0
- agno/models/aws/bedrock.py +701 -0
- agno/models/aws/claude.py +378 -0
- agno/models/azure/__init__.py +18 -0
- agno/models/azure/ai_foundry.py +485 -0
- agno/models/azure/openai_chat.py +131 -0
- agno/models/base.py +2175 -0
- agno/models/cerebras/__init__.py +12 -0
- agno/models/cerebras/cerebras.py +501 -0
- agno/models/cerebras/cerebras_openai.py +112 -0
- agno/models/cohere/__init__.py +5 -0
- agno/models/cohere/chat.py +389 -0
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +57 -0
- agno/models/dashscope/__init__.py +5 -0
- agno/models/dashscope/dashscope.py +91 -0
- agno/models/deepinfra/__init__.py +5 -0
- agno/models/deepinfra/deepinfra.py +28 -0
- agno/models/deepseek/__init__.py +5 -0
- agno/models/deepseek/deepseek.py +61 -0
- agno/models/defaults.py +1 -0
- agno/models/fireworks/__init__.py +5 -0
- agno/models/fireworks/fireworks.py +26 -0
- agno/models/google/__init__.py +5 -0
- agno/models/google/gemini.py +1085 -0
- agno/models/groq/__init__.py +5 -0
- agno/models/groq/groq.py +556 -0
- agno/models/huggingface/__init__.py +5 -0
- agno/models/huggingface/huggingface.py +491 -0
- agno/models/ibm/__init__.py +5 -0
- agno/models/ibm/watsonx.py +422 -0
- agno/models/internlm/__init__.py +3 -0
- agno/models/internlm/internlm.py +26 -0
- agno/models/langdb/__init__.py +1 -0
- agno/models/langdb/langdb.py +48 -0
- agno/models/litellm/__init__.py +14 -0
- agno/models/litellm/chat.py +468 -0
- agno/models/litellm/litellm_openai.py +25 -0
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/lmstudio/__init__.py +5 -0
- agno/models/lmstudio/lmstudio.py +25 -0
- agno/models/message.py +434 -0
- agno/models/meta/__init__.py +12 -0
- agno/models/meta/llama.py +475 -0
- agno/models/meta/llama_openai.py +78 -0
- agno/models/metrics.py +120 -0
- agno/models/mistral/__init__.py +5 -0
- agno/models/mistral/mistral.py +432 -0
- agno/models/nebius/__init__.py +3 -0
- agno/models/nebius/nebius.py +54 -0
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/__init__.py +5 -0
- agno/models/nvidia/nvidia.py +28 -0
- agno/models/ollama/__init__.py +5 -0
- agno/models/ollama/chat.py +441 -0
- agno/models/openai/__init__.py +9 -0
- agno/models/openai/chat.py +883 -0
- agno/models/openai/like.py +27 -0
- agno/models/openai/responses.py +1050 -0
- agno/models/openrouter/__init__.py +5 -0
- agno/models/openrouter/openrouter.py +66 -0
- agno/models/perplexity/__init__.py +5 -0
- agno/models/perplexity/perplexity.py +187 -0
- agno/models/portkey/__init__.py +3 -0
- agno/models/portkey/portkey.py +81 -0
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +52 -0
- agno/models/response.py +199 -0
- agno/models/sambanova/__init__.py +5 -0
- agno/models/sambanova/sambanova.py +28 -0
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +25 -0
- agno/models/together/__init__.py +5 -0
- agno/models/together/together.py +25 -0
- agno/models/utils.py +266 -0
- agno/models/vercel/__init__.py +3 -0
- agno/models/vercel/v0.py +26 -0
- agno/models/vertexai/__init__.py +0 -0
- agno/models/vertexai/claude.py +70 -0
- agno/models/vllm/__init__.py +3 -0
- agno/models/vllm/vllm.py +78 -0
- agno/models/xai/__init__.py +3 -0
- agno/models/xai/xai.py +113 -0
- agno/os/__init__.py +3 -0
- agno/os/app.py +876 -0
- agno/os/auth.py +57 -0
- agno/os/config.py +104 -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/__init__.py +3 -0
- agno/os/interfaces/agui/agui.py +47 -0
- agno/os/interfaces/agui/router.py +144 -0
- agno/os/interfaces/agui/utils.py +534 -0
- agno/os/interfaces/base.py +25 -0
- agno/os/interfaces/slack/__init__.py +3 -0
- agno/os/interfaces/slack/router.py +148 -0
- agno/os/interfaces/slack/security.py +30 -0
- agno/os/interfaces/slack/slack.py +47 -0
- agno/os/interfaces/whatsapp/__init__.py +3 -0
- agno/os/interfaces/whatsapp/router.py +211 -0
- agno/os/interfaces/whatsapp/security.py +53 -0
- agno/os/interfaces/whatsapp/whatsapp.py +36 -0
- agno/os/mcp.py +292 -0
- agno/os/middleware/__init__.py +7 -0
- agno/os/middleware/jwt.py +233 -0
- agno/os/router.py +1763 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +430 -0
- agno/os/routers/evals/schemas.py +142 -0
- agno/os/routers/evals/utils.py +162 -0
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/__init__.py +3 -0
- agno/os/routers/knowledge/knowledge.py +997 -0
- agno/os/routers/knowledge/schemas.py +178 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +515 -0
- agno/os/routers/memory/schemas.py +62 -0
- agno/os/routers/metrics/__init__.py +3 -0
- agno/os/routers/metrics/metrics.py +190 -0
- agno/os/routers/metrics/schemas.py +47 -0
- agno/os/routers/session/__init__.py +3 -0
- agno/os/routers/session/session.py +997 -0
- agno/os/schema.py +1055 -0
- agno/os/settings.py +43 -0
- agno/os/utils.py +630 -0
- agno/py.typed +0 -0
- agno/reasoning/__init__.py +0 -0
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +67 -0
- agno/reasoning/deepseek.py +63 -0
- agno/reasoning/default.py +97 -0
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +71 -0
- agno/reasoning/helpers.py +63 -0
- agno/reasoning/ollama.py +67 -0
- agno/reasoning/openai.py +86 -0
- agno/reasoning/step.py +31 -0
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +787 -0
- agno/run/base.py +229 -0
- agno/run/cancel.py +81 -0
- agno/run/messages.py +32 -0
- agno/run/team.py +753 -0
- agno/run/workflow.py +708 -0
- agno/session/__init__.py +10 -0
- agno/session/agent.py +295 -0
- agno/session/summary.py +265 -0
- agno/session/team.py +392 -0
- agno/session/workflow.py +205 -0
- agno/team/__init__.py +37 -0
- agno/team/team.py +8793 -0
- agno/tools/__init__.py +10 -0
- agno/tools/agentql.py +120 -0
- agno/tools/airflow.py +69 -0
- agno/tools/api.py +122 -0
- agno/tools/apify.py +314 -0
- agno/tools/arxiv.py +127 -0
- agno/tools/aws_lambda.py +53 -0
- agno/tools/aws_ses.py +66 -0
- agno/tools/baidusearch.py +89 -0
- agno/tools/bitbucket.py +292 -0
- agno/tools/brandfetch.py +213 -0
- agno/tools/bravesearch.py +106 -0
- agno/tools/brightdata.py +367 -0
- agno/tools/browserbase.py +209 -0
- agno/tools/calcom.py +255 -0
- agno/tools/calculator.py +151 -0
- agno/tools/cartesia.py +187 -0
- agno/tools/clickup.py +244 -0
- agno/tools/confluence.py +240 -0
- agno/tools/crawl4ai.py +158 -0
- agno/tools/csv_toolkit.py +185 -0
- agno/tools/dalle.py +110 -0
- agno/tools/daytona.py +475 -0
- agno/tools/decorator.py +262 -0
- agno/tools/desi_vocal.py +108 -0
- agno/tools/discord.py +161 -0
- agno/tools/docker.py +716 -0
- agno/tools/duckdb.py +379 -0
- agno/tools/duckduckgo.py +91 -0
- agno/tools/e2b.py +703 -0
- agno/tools/eleven_labs.py +196 -0
- agno/tools/email.py +67 -0
- agno/tools/evm.py +129 -0
- agno/tools/exa.py +396 -0
- agno/tools/fal.py +127 -0
- agno/tools/file.py +240 -0
- agno/tools/file_generation.py +350 -0
- agno/tools/financial_datasets.py +288 -0
- agno/tools/firecrawl.py +143 -0
- agno/tools/function.py +1187 -0
- agno/tools/giphy.py +93 -0
- agno/tools/github.py +1760 -0
- agno/tools/gmail.py +922 -0
- agno/tools/google_bigquery.py +117 -0
- agno/tools/google_drive.py +270 -0
- agno/tools/google_maps.py +253 -0
- agno/tools/googlecalendar.py +674 -0
- agno/tools/googlesearch.py +98 -0
- agno/tools/googlesheets.py +377 -0
- agno/tools/hackernews.py +77 -0
- agno/tools/jina.py +101 -0
- agno/tools/jira.py +170 -0
- agno/tools/knowledge.py +218 -0
- agno/tools/linear.py +426 -0
- agno/tools/linkup.py +58 -0
- agno/tools/local_file_system.py +90 -0
- agno/tools/lumalab.py +183 -0
- 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 +193 -0
- agno/tools/memori.py +339 -0
- agno/tools/memory.py +419 -0
- agno/tools/mlx_transcribe.py +139 -0
- agno/tools/models/__init__.py +0 -0
- agno/tools/models/azure_openai.py +190 -0
- agno/tools/models/gemini.py +203 -0
- agno/tools/models/groq.py +158 -0
- agno/tools/models/morph.py +186 -0
- agno/tools/models/nebius.py +124 -0
- agno/tools/models_labs.py +195 -0
- agno/tools/moviepy_video.py +349 -0
- agno/tools/neo4j.py +134 -0
- agno/tools/newspaper.py +46 -0
- agno/tools/newspaper4k.py +93 -0
- agno/tools/notion.py +204 -0
- agno/tools/openai.py +202 -0
- agno/tools/openbb.py +160 -0
- agno/tools/opencv.py +321 -0
- agno/tools/openweather.py +233 -0
- agno/tools/oxylabs.py +385 -0
- agno/tools/pandas.py +102 -0
- agno/tools/parallel.py +314 -0
- agno/tools/postgres.py +257 -0
- agno/tools/pubmed.py +188 -0
- agno/tools/python.py +205 -0
- agno/tools/reasoning.py +283 -0
- agno/tools/reddit.py +467 -0
- agno/tools/replicate.py +117 -0
- agno/tools/resend.py +62 -0
- agno/tools/scrapegraph.py +222 -0
- agno/tools/searxng.py +152 -0
- agno/tools/serpapi.py +116 -0
- agno/tools/serper.py +255 -0
- agno/tools/shell.py +53 -0
- agno/tools/slack.py +136 -0
- agno/tools/sleep.py +20 -0
- agno/tools/spider.py +116 -0
- agno/tools/sql.py +154 -0
- agno/tools/streamlit/__init__.py +0 -0
- agno/tools/streamlit/components.py +113 -0
- agno/tools/tavily.py +254 -0
- agno/tools/telegram.py +48 -0
- agno/tools/todoist.py +218 -0
- agno/tools/tool_registry.py +1 -0
- agno/tools/toolkit.py +146 -0
- agno/tools/trafilatura.py +388 -0
- agno/tools/trello.py +274 -0
- agno/tools/twilio.py +186 -0
- agno/tools/user_control_flow.py +78 -0
- agno/tools/valyu.py +228 -0
- agno/tools/visualization.py +467 -0
- agno/tools/webbrowser.py +28 -0
- agno/tools/webex.py +76 -0
- agno/tools/website.py +54 -0
- agno/tools/webtools.py +45 -0
- agno/tools/whatsapp.py +286 -0
- agno/tools/wikipedia.py +63 -0
- agno/tools/workflow.py +278 -0
- agno/tools/x.py +335 -0
- agno/tools/yfinance.py +257 -0
- agno/tools/youtube.py +184 -0
- agno/tools/zendesk.py +82 -0
- agno/tools/zep.py +454 -0
- agno/tools/zoom.py +382 -0
- agno/utils/__init__.py +0 -0
- agno/utils/agent.py +820 -0
- agno/utils/audio.py +49 -0
- agno/utils/certs.py +27 -0
- agno/utils/code_execution.py +11 -0
- agno/utils/common.py +132 -0
- agno/utils/dttm.py +13 -0
- agno/utils/enum.py +22 -0
- agno/utils/env.py +11 -0
- agno/utils/events.py +696 -0
- agno/utils/format_str.py +16 -0
- agno/utils/functions.py +166 -0
- agno/utils/gemini.py +426 -0
- agno/utils/hooks.py +57 -0
- agno/utils/http.py +74 -0
- agno/utils/json_schema.py +234 -0
- agno/utils/knowledge.py +36 -0
- agno/utils/location.py +19 -0
- agno/utils/log.py +255 -0
- agno/utils/mcp.py +214 -0
- agno/utils/media.py +352 -0
- agno/utils/merge_dict.py +41 -0
- agno/utils/message.py +118 -0
- agno/utils/models/__init__.py +0 -0
- agno/utils/models/ai_foundry.py +43 -0
- agno/utils/models/claude.py +358 -0
- agno/utils/models/cohere.py +87 -0
- agno/utils/models/llama.py +78 -0
- agno/utils/models/mistral.py +98 -0
- agno/utils/models/openai_responses.py +140 -0
- agno/utils/models/schema_utils.py +153 -0
- agno/utils/models/watsonx.py +41 -0
- agno/utils/openai.py +257 -0
- agno/utils/pickle.py +32 -0
- agno/utils/pprint.py +178 -0
- agno/utils/print_response/__init__.py +0 -0
- agno/utils/print_response/agent.py +842 -0
- agno/utils/print_response/team.py +1724 -0
- agno/utils/print_response/workflow.py +1668 -0
- agno/utils/prompts.py +111 -0
- agno/utils/reasoning.py +108 -0
- agno/utils/response.py +163 -0
- agno/utils/response_iterator.py +17 -0
- agno/utils/safe_formatter.py +24 -0
- agno/utils/serialize.py +32 -0
- agno/utils/shell.py +22 -0
- agno/utils/streamlit.py +487 -0
- agno/utils/string.py +231 -0
- agno/utils/team.py +139 -0
- agno/utils/timer.py +41 -0
- agno/utils/tools.py +102 -0
- agno/utils/web.py +23 -0
- agno/utils/whatsapp.py +305 -0
- agno/utils/yaml_io.py +25 -0
- agno/vectordb/__init__.py +3 -0
- agno/vectordb/base.py +127 -0
- agno/vectordb/cassandra/__init__.py +5 -0
- agno/vectordb/cassandra/cassandra.py +501 -0
- agno/vectordb/cassandra/extra_param_mixin.py +11 -0
- agno/vectordb/cassandra/index.py +13 -0
- agno/vectordb/chroma/__init__.py +5 -0
- agno/vectordb/chroma/chromadb.py +929 -0
- agno/vectordb/clickhouse/__init__.py +9 -0
- agno/vectordb/clickhouse/clickhousedb.py +835 -0
- agno/vectordb/clickhouse/index.py +9 -0
- agno/vectordb/couchbase/__init__.py +3 -0
- agno/vectordb/couchbase/couchbase.py +1442 -0
- agno/vectordb/distance.py +7 -0
- agno/vectordb/lancedb/__init__.py +6 -0
- agno/vectordb/lancedb/lance_db.py +995 -0
- agno/vectordb/langchaindb/__init__.py +5 -0
- agno/vectordb/langchaindb/langchaindb.py +163 -0
- agno/vectordb/lightrag/__init__.py +5 -0
- agno/vectordb/lightrag/lightrag.py +388 -0
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +166 -0
- agno/vectordb/milvus/__init__.py +4 -0
- agno/vectordb/milvus/milvus.py +1182 -0
- agno/vectordb/mongodb/__init__.py +9 -0
- agno/vectordb/mongodb/mongodb.py +1417 -0
- agno/vectordb/pgvector/__init__.py +12 -0
- agno/vectordb/pgvector/index.py +23 -0
- agno/vectordb/pgvector/pgvector.py +1462 -0
- agno/vectordb/pineconedb/__init__.py +5 -0
- agno/vectordb/pineconedb/pineconedb.py +747 -0
- agno/vectordb/qdrant/__init__.py +5 -0
- agno/vectordb/qdrant/qdrant.py +1134 -0
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +694 -0
- agno/vectordb/search.py +7 -0
- agno/vectordb/singlestore/__init__.py +10 -0
- agno/vectordb/singlestore/index.py +41 -0
- agno/vectordb/singlestore/singlestore.py +763 -0
- agno/vectordb/surrealdb/__init__.py +3 -0
- agno/vectordb/surrealdb/surrealdb.py +699 -0
- agno/vectordb/upstashdb/__init__.py +5 -0
- agno/vectordb/upstashdb/upstashdb.py +718 -0
- agno/vectordb/weaviate/__init__.py +8 -0
- agno/vectordb/weaviate/index.py +15 -0
- agno/vectordb/weaviate/weaviate.py +1005 -0
- agno/workflow/__init__.py +23 -0
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +738 -0
- agno/workflow/loop.py +735 -0
- agno/workflow/parallel.py +824 -0
- agno/workflow/router.py +702 -0
- agno/workflow/step.py +1432 -0
- agno/workflow/steps.py +592 -0
- agno/workflow/types.py +520 -0
- agno/workflow/workflow.py +4321 -0
- agno-2.2.13.dist-info/METADATA +614 -0
- agno-2.2.13.dist-info/RECORD +575 -0
- agno-2.2.13.dist-info/WHEEL +5 -0
- agno-2.2.13.dist-info/licenses/LICENSE +201 -0
- agno-2.2.13.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,757 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from collections.abc import AsyncIterator
|
|
3
|
+
from dataclasses import asdict, dataclass
|
|
4
|
+
from os import getenv
|
|
5
|
+
from typing import Any, Dict, List, Optional, Type, Union
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
|
|
9
|
+
from agno.exceptions import ModelProviderError, ModelRateLimitError
|
|
10
|
+
from agno.models.base import Model
|
|
11
|
+
from agno.models.message import Citations, DocumentCitation, Message, UrlCitation
|
|
12
|
+
from agno.models.metrics import Metrics
|
|
13
|
+
from agno.models.response import ModelResponse
|
|
14
|
+
from agno.run.agent import RunOutput
|
|
15
|
+
from agno.utils.log import log_debug, log_error, log_warning
|
|
16
|
+
from agno.utils.models.claude import MCPServerConfiguration, format_messages, format_tools_for_model
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
from anthropic import Anthropic as AnthropicClient
|
|
20
|
+
from anthropic import (
|
|
21
|
+
APIConnectionError,
|
|
22
|
+
APIStatusError,
|
|
23
|
+
RateLimitError,
|
|
24
|
+
)
|
|
25
|
+
from anthropic import (
|
|
26
|
+
AsyncAnthropic as AsyncAnthropicClient,
|
|
27
|
+
)
|
|
28
|
+
from anthropic.types import (
|
|
29
|
+
CitationPageLocation,
|
|
30
|
+
CitationsWebSearchResultLocation,
|
|
31
|
+
ContentBlockDeltaEvent,
|
|
32
|
+
ContentBlockStartEvent,
|
|
33
|
+
ContentBlockStopEvent,
|
|
34
|
+
MessageDeltaUsage,
|
|
35
|
+
# MessageDeltaEvent, # Currently broken
|
|
36
|
+
MessageStopEvent,
|
|
37
|
+
Usage,
|
|
38
|
+
)
|
|
39
|
+
from anthropic.types import (
|
|
40
|
+
Message as AnthropicMessage,
|
|
41
|
+
)
|
|
42
|
+
except ImportError as e:
|
|
43
|
+
raise ImportError("`anthropic` not installed. Please install it with `pip install anthropic`") from e
|
|
44
|
+
|
|
45
|
+
# Import Beta types
|
|
46
|
+
try:
|
|
47
|
+
from anthropic.types.beta import BetaRawContentBlockDeltaEvent, BetaTextDelta
|
|
48
|
+
from anthropic.types.beta.beta_message import BetaMessage
|
|
49
|
+
from anthropic.types.beta.beta_usage import BetaUsage
|
|
50
|
+
except ImportError as e:
|
|
51
|
+
raise ImportError(
|
|
52
|
+
"`anthropic` not installed or missing beta components. Please install with `pip install anthropic`"
|
|
53
|
+
) from e
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass
|
|
57
|
+
class Claude(Model):
|
|
58
|
+
"""
|
|
59
|
+
A class representing Anthropic Claude model.
|
|
60
|
+
|
|
61
|
+
For more information, see: https://docs.anthropic.com/en/api/messages
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
# Models that DO NOT support extended thinking
|
|
65
|
+
# All future models are assumed to support thinking
|
|
66
|
+
# Based on official Anthropic documentation: https://docs.claude.com/en/docs/about-claude/models/overview
|
|
67
|
+
NON_THINKING_MODELS = {
|
|
68
|
+
# Claude Haiku 3 family (does not support thinking)
|
|
69
|
+
"claude-3-haiku-20240307",
|
|
70
|
+
# Claude Haiku 3.5 family (does not support thinking)
|
|
71
|
+
"claude-3-5-haiku-20241022",
|
|
72
|
+
"claude-3-5-haiku-latest",
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
id: str = "claude-sonnet-4-5-20250929"
|
|
76
|
+
name: str = "Claude"
|
|
77
|
+
provider: str = "Anthropic"
|
|
78
|
+
|
|
79
|
+
# Request parameters
|
|
80
|
+
max_tokens: Optional[int] = 8192
|
|
81
|
+
thinking: Optional[Dict[str, Any]] = None
|
|
82
|
+
temperature: Optional[float] = None
|
|
83
|
+
stop_sequences: Optional[List[str]] = None
|
|
84
|
+
top_p: Optional[float] = None
|
|
85
|
+
top_k: Optional[int] = None
|
|
86
|
+
cache_system_prompt: Optional[bool] = False
|
|
87
|
+
extended_cache_time: Optional[bool] = False
|
|
88
|
+
request_params: Optional[Dict[str, Any]] = None
|
|
89
|
+
|
|
90
|
+
# Anthropic beta and experimental features
|
|
91
|
+
betas: Optional[List[str]] = None # Enables specific experimental or newly released features.
|
|
92
|
+
context_management: Optional[Dict[str, Any]] = None
|
|
93
|
+
mcp_servers: Optional[List[MCPServerConfiguration]] = None
|
|
94
|
+
skills: Optional[List[Dict[str, str]]] = (
|
|
95
|
+
None # e.g., [{"type": "anthropic", "skill_id": "pptx", "version": "latest"}]
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# Client parameters
|
|
99
|
+
api_key: Optional[str] = None
|
|
100
|
+
default_headers: Optional[Dict[str, Any]] = None
|
|
101
|
+
timeout: Optional[float] = None
|
|
102
|
+
client_params: Optional[Dict[str, Any]] = None
|
|
103
|
+
|
|
104
|
+
client: Optional[AnthropicClient] = None
|
|
105
|
+
async_client: Optional[AsyncAnthropicClient] = None
|
|
106
|
+
|
|
107
|
+
def __post_init__(self):
|
|
108
|
+
"""Validate model configuration after initialization"""
|
|
109
|
+
# Validate thinking support immediately at model creation
|
|
110
|
+
if self.thinking:
|
|
111
|
+
self._validate_thinking_support()
|
|
112
|
+
# Set up skills configuration if skills are enabled
|
|
113
|
+
if self.skills:
|
|
114
|
+
self._setup_skills_configuration()
|
|
115
|
+
|
|
116
|
+
def _get_client_params(self) -> Dict[str, Any]:
|
|
117
|
+
client_params: Dict[str, Any] = {}
|
|
118
|
+
|
|
119
|
+
self.api_key = self.api_key or getenv("ANTHROPIC_API_KEY")
|
|
120
|
+
if not self.api_key:
|
|
121
|
+
log_error("ANTHROPIC_API_KEY not set. Please set the ANTHROPIC_API_KEY environment variable.")
|
|
122
|
+
|
|
123
|
+
# Add API key to client parameters
|
|
124
|
+
client_params["api_key"] = self.api_key
|
|
125
|
+
if self.timeout is not None:
|
|
126
|
+
client_params["timeout"] = self.timeout
|
|
127
|
+
|
|
128
|
+
# Add additional client parameters
|
|
129
|
+
if self.client_params is not None:
|
|
130
|
+
client_params.update(self.client_params)
|
|
131
|
+
if self.default_headers is not None:
|
|
132
|
+
client_params["default_headers"] = self.default_headers
|
|
133
|
+
return client_params
|
|
134
|
+
|
|
135
|
+
def _has_beta_features(self) -> bool:
|
|
136
|
+
"""Check if the model has any Anthropic beta features enabled."""
|
|
137
|
+
return (
|
|
138
|
+
self.mcp_servers is not None
|
|
139
|
+
or self.context_management is not None
|
|
140
|
+
or self.skills is not None
|
|
141
|
+
or self.betas is not None
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
def get_client(self) -> AnthropicClient:
|
|
145
|
+
"""
|
|
146
|
+
Returns an instance of the Anthropic client.
|
|
147
|
+
"""
|
|
148
|
+
if self.client and not self.client.is_closed():
|
|
149
|
+
return self.client
|
|
150
|
+
|
|
151
|
+
_client_params = self._get_client_params()
|
|
152
|
+
self.client = AnthropicClient(**_client_params)
|
|
153
|
+
return self.client
|
|
154
|
+
|
|
155
|
+
def get_async_client(self) -> AsyncAnthropicClient:
|
|
156
|
+
"""
|
|
157
|
+
Returns an instance of the async Anthropic client.
|
|
158
|
+
"""
|
|
159
|
+
if self.async_client and not self.async_client.is_closed():
|
|
160
|
+
return self.async_client
|
|
161
|
+
|
|
162
|
+
_client_params = self._get_client_params()
|
|
163
|
+
self.async_client = AsyncAnthropicClient(**_client_params)
|
|
164
|
+
return self.async_client
|
|
165
|
+
|
|
166
|
+
def _validate_thinking_support(self) -> None:
|
|
167
|
+
"""
|
|
168
|
+
Validate that the current model supports extended thinking.
|
|
169
|
+
|
|
170
|
+
Raises:
|
|
171
|
+
ValueError: If thinking is enabled but the model doesn't support it
|
|
172
|
+
"""
|
|
173
|
+
if self.thinking and self.id in self.NON_THINKING_MODELS:
|
|
174
|
+
non_thinking_models = "\n - ".join(sorted(self.NON_THINKING_MODELS))
|
|
175
|
+
raise ValueError(
|
|
176
|
+
f"Model '{self.id}' does not support extended thinking.\n\n"
|
|
177
|
+
f"The following models do NOT support thinking:\n - {non_thinking_models}\n\n"
|
|
178
|
+
f"All other Claude models support extended thinking by default.\n"
|
|
179
|
+
f"For more information, see: https://docs.anthropic.com/en/docs/about-claude/models/overview"
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
def _setup_skills_configuration(self) -> None:
|
|
183
|
+
"""
|
|
184
|
+
Set up configuration for Claude Agent Skills.
|
|
185
|
+
Automatically configures betas array with required values.
|
|
186
|
+
|
|
187
|
+
Skills enable document creation capabilities (PowerPoint, Excel, Word, PDF).
|
|
188
|
+
For more information, see: https://docs.claude.com/en/docs/agents-and-tools/agent-skills/quickstart
|
|
189
|
+
"""
|
|
190
|
+
# Required betas for skills
|
|
191
|
+
required_betas = ["code-execution-2025-08-25", "skills-2025-10-02"]
|
|
192
|
+
|
|
193
|
+
# Initialize or merge betas
|
|
194
|
+
if self.betas is None:
|
|
195
|
+
self.betas = required_betas
|
|
196
|
+
else:
|
|
197
|
+
# Add required betas if not present
|
|
198
|
+
for beta in required_betas:
|
|
199
|
+
if beta not in self.betas:
|
|
200
|
+
self.betas.append(beta)
|
|
201
|
+
|
|
202
|
+
def get_request_params(self) -> Dict[str, Any]:
|
|
203
|
+
"""
|
|
204
|
+
Generate keyword arguments for API requests.
|
|
205
|
+
"""
|
|
206
|
+
# Validate thinking support if thinking is enabled
|
|
207
|
+
if self.thinking:
|
|
208
|
+
self._validate_thinking_support()
|
|
209
|
+
|
|
210
|
+
_request_params: Dict[str, Any] = {}
|
|
211
|
+
if self.max_tokens:
|
|
212
|
+
_request_params["max_tokens"] = self.max_tokens
|
|
213
|
+
if self.thinking:
|
|
214
|
+
_request_params["thinking"] = self.thinking
|
|
215
|
+
if self.temperature:
|
|
216
|
+
_request_params["temperature"] = self.temperature
|
|
217
|
+
if self.stop_sequences:
|
|
218
|
+
_request_params["stop_sequences"] = self.stop_sequences
|
|
219
|
+
if self.top_p:
|
|
220
|
+
_request_params["top_p"] = self.top_p
|
|
221
|
+
if self.top_k:
|
|
222
|
+
_request_params["top_k"] = self.top_k
|
|
223
|
+
if self.betas:
|
|
224
|
+
_request_params["betas"] = self.betas
|
|
225
|
+
if self.context_management:
|
|
226
|
+
_request_params["context_management"] = self.context_management
|
|
227
|
+
if self.mcp_servers:
|
|
228
|
+
_request_params["mcp_servers"] = [
|
|
229
|
+
{k: v for k, v in asdict(server).items() if v is not None} for server in self.mcp_servers
|
|
230
|
+
]
|
|
231
|
+
if self.skills:
|
|
232
|
+
_request_params["betas"] = self.betas
|
|
233
|
+
_request_params["container"] = {"skills": self.skills}
|
|
234
|
+
if self.request_params:
|
|
235
|
+
_request_params.update(self.request_params)
|
|
236
|
+
|
|
237
|
+
return _request_params
|
|
238
|
+
|
|
239
|
+
def _prepare_request_kwargs(
|
|
240
|
+
self, system_message: str, tools: Optional[List[Dict[str, Any]]] = None
|
|
241
|
+
) -> Dict[str, Any]:
|
|
242
|
+
"""
|
|
243
|
+
Prepare the request keyword arguments for the API call.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
system_message (str): The concatenated system messages.
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
Dict[str, Any]: The request keyword arguments.
|
|
250
|
+
"""
|
|
251
|
+
request_kwargs = self.get_request_params().copy()
|
|
252
|
+
if system_message:
|
|
253
|
+
if self.cache_system_prompt:
|
|
254
|
+
cache_control = (
|
|
255
|
+
{"type": "ephemeral", "ttl": "1h"}
|
|
256
|
+
if self.extended_cache_time is not None and self.extended_cache_time is True
|
|
257
|
+
else {"type": "ephemeral"}
|
|
258
|
+
)
|
|
259
|
+
request_kwargs["system"] = [{"text": system_message, "type": "text", "cache_control": cache_control}]
|
|
260
|
+
else:
|
|
261
|
+
request_kwargs["system"] = [{"text": system_message, "type": "text"}]
|
|
262
|
+
|
|
263
|
+
# Add code execution tool if skills are enabled
|
|
264
|
+
if self.skills:
|
|
265
|
+
code_execution_tool = {"type": "code_execution_20250825", "name": "code_execution"}
|
|
266
|
+
if tools:
|
|
267
|
+
# Add code_execution to existing tools, code execution is needed for generating and processing files
|
|
268
|
+
tools = tools + [code_execution_tool]
|
|
269
|
+
else:
|
|
270
|
+
tools = [code_execution_tool]
|
|
271
|
+
|
|
272
|
+
if tools:
|
|
273
|
+
request_kwargs["tools"] = format_tools_for_model(tools)
|
|
274
|
+
|
|
275
|
+
if request_kwargs:
|
|
276
|
+
log_debug(f"Calling {self.provider} with request parameters: {request_kwargs}", log_level=2)
|
|
277
|
+
return request_kwargs
|
|
278
|
+
|
|
279
|
+
def invoke(
|
|
280
|
+
self,
|
|
281
|
+
messages: List[Message],
|
|
282
|
+
assistant_message: Message,
|
|
283
|
+
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
284
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
285
|
+
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
286
|
+
run_response: Optional[RunOutput] = None,
|
|
287
|
+
) -> ModelResponse:
|
|
288
|
+
"""
|
|
289
|
+
Send a request to the Anthropic API to generate a response.
|
|
290
|
+
"""
|
|
291
|
+
try:
|
|
292
|
+
if run_response and run_response.metrics:
|
|
293
|
+
run_response.metrics.set_time_to_first_token()
|
|
294
|
+
|
|
295
|
+
chat_messages, system_message = format_messages(messages)
|
|
296
|
+
request_kwargs = self._prepare_request_kwargs(system_message, tools)
|
|
297
|
+
|
|
298
|
+
if self._has_beta_features():
|
|
299
|
+
assistant_message.metrics.start_timer()
|
|
300
|
+
provider_response = self.get_client().beta.messages.create(
|
|
301
|
+
model=self.id,
|
|
302
|
+
messages=chat_messages, # type: ignore
|
|
303
|
+
**request_kwargs,
|
|
304
|
+
)
|
|
305
|
+
else:
|
|
306
|
+
assistant_message.metrics.start_timer()
|
|
307
|
+
provider_response = self.get_client().messages.create(
|
|
308
|
+
model=self.id,
|
|
309
|
+
messages=chat_messages, # type: ignore
|
|
310
|
+
**request_kwargs,
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
assistant_message.metrics.stop_timer()
|
|
314
|
+
|
|
315
|
+
# Parse the response into an Agno ModelResponse object
|
|
316
|
+
model_response = self._parse_provider_response(provider_response, response_format=response_format) # type: ignore
|
|
317
|
+
|
|
318
|
+
return model_response
|
|
319
|
+
|
|
320
|
+
except APIConnectionError as e:
|
|
321
|
+
log_error(f"Connection error while calling Claude API: {str(e)}")
|
|
322
|
+
raise ModelProviderError(message=e.message, model_name=self.name, model_id=self.id) from e
|
|
323
|
+
except RateLimitError as e:
|
|
324
|
+
log_warning(f"Rate limit exceeded: {str(e)}")
|
|
325
|
+
raise ModelRateLimitError(message=e.message, model_name=self.name, model_id=self.id) from e
|
|
326
|
+
except APIStatusError as e:
|
|
327
|
+
log_error(f"Claude API error (status {e.status_code}): {str(e)}")
|
|
328
|
+
raise ModelProviderError(
|
|
329
|
+
message=e.message, status_code=e.status_code, model_name=self.name, model_id=self.id
|
|
330
|
+
) from e
|
|
331
|
+
except Exception as e:
|
|
332
|
+
log_error(f"Unexpected error calling Claude API: {str(e)}")
|
|
333
|
+
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
334
|
+
|
|
335
|
+
def invoke_stream(
|
|
336
|
+
self,
|
|
337
|
+
messages: List[Message],
|
|
338
|
+
assistant_message: Message,
|
|
339
|
+
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
340
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
341
|
+
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
342
|
+
run_response: Optional[RunOutput] = None,
|
|
343
|
+
) -> Any:
|
|
344
|
+
"""
|
|
345
|
+
Stream a response from the Anthropic API.
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
messages (List[Message]): A list of messages to send to the model.
|
|
349
|
+
|
|
350
|
+
Returns:
|
|
351
|
+
Any: The streamed response from the model.
|
|
352
|
+
|
|
353
|
+
Raises:
|
|
354
|
+
APIConnectionError: If there are network connectivity issues
|
|
355
|
+
RateLimitError: If the API rate limit is exceeded
|
|
356
|
+
APIStatusError: For other API-related errors
|
|
357
|
+
"""
|
|
358
|
+
chat_messages, system_message = format_messages(messages)
|
|
359
|
+
request_kwargs = self._prepare_request_kwargs(system_message, tools)
|
|
360
|
+
|
|
361
|
+
try:
|
|
362
|
+
if run_response and run_response.metrics:
|
|
363
|
+
run_response.metrics.set_time_to_first_token()
|
|
364
|
+
|
|
365
|
+
# Beta features
|
|
366
|
+
if self._has_beta_features():
|
|
367
|
+
assistant_message.metrics.start_timer()
|
|
368
|
+
with self.get_client().beta.messages.stream(
|
|
369
|
+
model=self.id,
|
|
370
|
+
messages=chat_messages, # type: ignore
|
|
371
|
+
**request_kwargs,
|
|
372
|
+
) as stream:
|
|
373
|
+
for chunk in stream:
|
|
374
|
+
yield self._parse_provider_response_delta(chunk) # type: ignore
|
|
375
|
+
else:
|
|
376
|
+
assistant_message.metrics.start_timer()
|
|
377
|
+
with self.get_client().messages.stream(
|
|
378
|
+
model=self.id,
|
|
379
|
+
messages=chat_messages, # type: ignore
|
|
380
|
+
**request_kwargs,
|
|
381
|
+
) as stream:
|
|
382
|
+
for chunk in stream: # type: ignore
|
|
383
|
+
yield self._parse_provider_response_delta(chunk) # type: ignore
|
|
384
|
+
|
|
385
|
+
assistant_message.metrics.stop_timer()
|
|
386
|
+
|
|
387
|
+
except APIConnectionError as e:
|
|
388
|
+
log_error(f"Connection error while calling Claude API: {str(e)}")
|
|
389
|
+
raise ModelProviderError(message=e.message, model_name=self.name, model_id=self.id) from e
|
|
390
|
+
except RateLimitError as e:
|
|
391
|
+
log_warning(f"Rate limit exceeded: {str(e)}")
|
|
392
|
+
raise ModelRateLimitError(message=e.message, model_name=self.name, model_id=self.id) from e
|
|
393
|
+
except APIStatusError as e:
|
|
394
|
+
log_error(f"Claude API error (status {e.status_code}): {str(e)}")
|
|
395
|
+
raise ModelProviderError(
|
|
396
|
+
message=e.message, status_code=e.status_code, model_name=self.name, model_id=self.id
|
|
397
|
+
) from e
|
|
398
|
+
except Exception as e:
|
|
399
|
+
log_error(f"Unexpected error calling Claude API: {str(e)}")
|
|
400
|
+
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
401
|
+
|
|
402
|
+
async def ainvoke(
|
|
403
|
+
self,
|
|
404
|
+
messages: List[Message],
|
|
405
|
+
assistant_message: Message,
|
|
406
|
+
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
407
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
408
|
+
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
409
|
+
run_response: Optional[RunOutput] = None,
|
|
410
|
+
) -> ModelResponse:
|
|
411
|
+
"""
|
|
412
|
+
Send an asynchronous request to the Anthropic API to generate a response.
|
|
413
|
+
"""
|
|
414
|
+
try:
|
|
415
|
+
if run_response and run_response.metrics:
|
|
416
|
+
run_response.metrics.set_time_to_first_token()
|
|
417
|
+
|
|
418
|
+
chat_messages, system_message = format_messages(messages)
|
|
419
|
+
request_kwargs = self._prepare_request_kwargs(system_message, tools)
|
|
420
|
+
|
|
421
|
+
# Beta features
|
|
422
|
+
if self._has_beta_features():
|
|
423
|
+
assistant_message.metrics.start_timer()
|
|
424
|
+
provider_response = await self.get_async_client().beta.messages.create(
|
|
425
|
+
model=self.id,
|
|
426
|
+
messages=chat_messages, # type: ignore
|
|
427
|
+
**request_kwargs,
|
|
428
|
+
)
|
|
429
|
+
else:
|
|
430
|
+
assistant_message.metrics.start_timer()
|
|
431
|
+
provider_response = await self.get_async_client().messages.create(
|
|
432
|
+
model=self.id,
|
|
433
|
+
messages=chat_messages, # type: ignore
|
|
434
|
+
**request_kwargs,
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
assistant_message.metrics.stop_timer()
|
|
438
|
+
|
|
439
|
+
# Parse the response into an Agno ModelResponse object
|
|
440
|
+
model_response = self._parse_provider_response(provider_response, response_format=response_format) # type: ignore
|
|
441
|
+
|
|
442
|
+
return model_response
|
|
443
|
+
|
|
444
|
+
except APIConnectionError as e:
|
|
445
|
+
log_error(f"Connection error while calling Claude API: {str(e)}")
|
|
446
|
+
raise ModelProviderError(message=e.message, model_name=self.name, model_id=self.id) from e
|
|
447
|
+
except RateLimitError as e:
|
|
448
|
+
log_warning(f"Rate limit exceeded: {str(e)}")
|
|
449
|
+
raise ModelRateLimitError(message=e.message, model_name=self.name, model_id=self.id) from e
|
|
450
|
+
except APIStatusError as e:
|
|
451
|
+
log_error(f"Claude API error (status {e.status_code}): {str(e)}")
|
|
452
|
+
raise ModelProviderError(
|
|
453
|
+
message=e.message, status_code=e.status_code, model_name=self.name, model_id=self.id
|
|
454
|
+
) from e
|
|
455
|
+
except Exception as e:
|
|
456
|
+
log_error(f"Unexpected error calling Claude API: {str(e)}")
|
|
457
|
+
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
458
|
+
|
|
459
|
+
async def ainvoke_stream(
|
|
460
|
+
self,
|
|
461
|
+
messages: List[Message],
|
|
462
|
+
assistant_message: Message,
|
|
463
|
+
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
464
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
465
|
+
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
466
|
+
run_response: Optional[RunOutput] = None,
|
|
467
|
+
) -> AsyncIterator[ModelResponse]:
|
|
468
|
+
"""
|
|
469
|
+
Stream an asynchronous response from the Anthropic API.
|
|
470
|
+
Args:
|
|
471
|
+
messages (List[Message]): A list of messages to send to the model.
|
|
472
|
+
Returns:
|
|
473
|
+
AsyncIterator[ModelResponse]: An async iterator of processed model responses.
|
|
474
|
+
Raises:
|
|
475
|
+
APIConnectionError: If there are network connectivity issues
|
|
476
|
+
RateLimitError: If the API rate limit is exceeded
|
|
477
|
+
APIStatusError: For other API-related errors
|
|
478
|
+
"""
|
|
479
|
+
try:
|
|
480
|
+
if run_response and run_response.metrics:
|
|
481
|
+
run_response.metrics.set_time_to_first_token()
|
|
482
|
+
|
|
483
|
+
chat_messages, system_message = format_messages(messages)
|
|
484
|
+
request_kwargs = self._prepare_request_kwargs(system_message, tools)
|
|
485
|
+
|
|
486
|
+
if self._has_beta_features():
|
|
487
|
+
assistant_message.metrics.start_timer()
|
|
488
|
+
async with self.get_async_client().beta.messages.stream(
|
|
489
|
+
model=self.id,
|
|
490
|
+
messages=chat_messages, # type: ignore
|
|
491
|
+
**request_kwargs,
|
|
492
|
+
) as stream:
|
|
493
|
+
async for chunk in stream:
|
|
494
|
+
yield self._parse_provider_response_delta(chunk) # type: ignore
|
|
495
|
+
else:
|
|
496
|
+
assistant_message.metrics.start_timer()
|
|
497
|
+
async with self.get_async_client().messages.stream(
|
|
498
|
+
model=self.id,
|
|
499
|
+
messages=chat_messages, # type: ignore
|
|
500
|
+
**request_kwargs,
|
|
501
|
+
) as stream:
|
|
502
|
+
async for chunk in stream: # type: ignore
|
|
503
|
+
yield self._parse_provider_response_delta(chunk) # type: ignore
|
|
504
|
+
|
|
505
|
+
assistant_message.metrics.stop_timer()
|
|
506
|
+
|
|
507
|
+
except APIConnectionError as e:
|
|
508
|
+
log_error(f"Connection error while calling Claude API: {str(e)}")
|
|
509
|
+
raise ModelProviderError(message=e.message, model_name=self.name, model_id=self.id) from e
|
|
510
|
+
except RateLimitError as e:
|
|
511
|
+
log_warning(f"Rate limit exceeded: {str(e)}")
|
|
512
|
+
raise ModelRateLimitError(message=e.message, model_name=self.name, model_id=self.id) from e
|
|
513
|
+
except APIStatusError as e:
|
|
514
|
+
log_error(f"Claude API error (status {e.status_code}): {str(e)}")
|
|
515
|
+
raise ModelProviderError(
|
|
516
|
+
message=e.message, status_code=e.status_code, model_name=self.name, model_id=self.id
|
|
517
|
+
) from e
|
|
518
|
+
except Exception as e:
|
|
519
|
+
log_error(f"Unexpected error calling Claude API: {str(e)}")
|
|
520
|
+
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
521
|
+
|
|
522
|
+
def get_system_message_for_model(self, tools: Optional[List[Any]] = None) -> Optional[str]:
|
|
523
|
+
if tools is not None and len(tools) > 0:
|
|
524
|
+
tool_call_prompt = "Do not reflect on the quality of the returned search results in your response\n\n"
|
|
525
|
+
return tool_call_prompt
|
|
526
|
+
return None
|
|
527
|
+
|
|
528
|
+
def _parse_provider_response(self, response: Union[AnthropicMessage, BetaMessage], **kwargs) -> ModelResponse:
|
|
529
|
+
"""
|
|
530
|
+
Parse the Claude response into a ModelResponse.
|
|
531
|
+
|
|
532
|
+
Args:
|
|
533
|
+
response: Raw response from Anthropic
|
|
534
|
+
|
|
535
|
+
Returns:
|
|
536
|
+
ModelResponse: Parsed response data
|
|
537
|
+
"""
|
|
538
|
+
model_response = ModelResponse()
|
|
539
|
+
|
|
540
|
+
# Add role (Claude always uses 'assistant')
|
|
541
|
+
model_response.role = response.role or "assistant"
|
|
542
|
+
|
|
543
|
+
if response.content:
|
|
544
|
+
for block in response.content:
|
|
545
|
+
if block.type == "text":
|
|
546
|
+
if model_response.content is None:
|
|
547
|
+
model_response.content = block.text
|
|
548
|
+
else:
|
|
549
|
+
model_response.content += block.text
|
|
550
|
+
|
|
551
|
+
# Capture citations from the response
|
|
552
|
+
if block.citations is not None:
|
|
553
|
+
if model_response.citations is None:
|
|
554
|
+
model_response.citations = Citations(raw=[], urls=[], documents=[])
|
|
555
|
+
for citation in block.citations:
|
|
556
|
+
model_response.citations.raw.append(citation.model_dump()) # type: ignore
|
|
557
|
+
# Web search citations
|
|
558
|
+
if isinstance(citation, CitationsWebSearchResultLocation):
|
|
559
|
+
model_response.citations.urls.append( # type: ignore
|
|
560
|
+
UrlCitation(url=citation.url, title=citation.cited_text)
|
|
561
|
+
)
|
|
562
|
+
# Document citations
|
|
563
|
+
elif isinstance(citation, CitationPageLocation):
|
|
564
|
+
model_response.citations.documents.append( # type: ignore
|
|
565
|
+
DocumentCitation(
|
|
566
|
+
document_title=citation.document_title,
|
|
567
|
+
cited_text=citation.cited_text,
|
|
568
|
+
)
|
|
569
|
+
)
|
|
570
|
+
elif block.type == "thinking":
|
|
571
|
+
model_response.reasoning_content = block.thinking
|
|
572
|
+
model_response.provider_data = {
|
|
573
|
+
"signature": block.signature,
|
|
574
|
+
}
|
|
575
|
+
elif block.type == "redacted_thinking":
|
|
576
|
+
model_response.redacted_reasoning_content = block.data
|
|
577
|
+
|
|
578
|
+
# Extract tool calls from the response
|
|
579
|
+
if response.stop_reason == "tool_use":
|
|
580
|
+
for block in response.content:
|
|
581
|
+
if block.type == "tool_use":
|
|
582
|
+
tool_name = block.name
|
|
583
|
+
tool_input = block.input
|
|
584
|
+
|
|
585
|
+
function_def = {"name": tool_name}
|
|
586
|
+
if tool_input:
|
|
587
|
+
function_def["arguments"] = json.dumps(tool_input)
|
|
588
|
+
|
|
589
|
+
model_response.extra = model_response.extra or {}
|
|
590
|
+
|
|
591
|
+
model_response.tool_calls.append(
|
|
592
|
+
{
|
|
593
|
+
"id": block.id,
|
|
594
|
+
"type": "function",
|
|
595
|
+
"function": function_def,
|
|
596
|
+
}
|
|
597
|
+
)
|
|
598
|
+
|
|
599
|
+
# Add usage metrics
|
|
600
|
+
if response.usage is not None:
|
|
601
|
+
model_response.response_usage = self._get_metrics(response.usage)
|
|
602
|
+
|
|
603
|
+
# Capture context management information if present
|
|
604
|
+
if self.context_management is not None and hasattr(response, "context_management"):
|
|
605
|
+
if response.context_management is not None: # type: ignore
|
|
606
|
+
model_response.provider_data = model_response.provider_data or {}
|
|
607
|
+
if hasattr(response.context_management, "model_dump"):
|
|
608
|
+
model_response.provider_data["context_management"] = response.context_management.model_dump() # type: ignore
|
|
609
|
+
else:
|
|
610
|
+
model_response.provider_data["context_management"] = response.context_management # type: ignore
|
|
611
|
+
# Extract file IDs if skills are enabled
|
|
612
|
+
if self.skills and response.content:
|
|
613
|
+
file_ids: List[str] = []
|
|
614
|
+
for block in response.content:
|
|
615
|
+
if block.type == "bash_code_execution_tool_result":
|
|
616
|
+
if hasattr(block, "content") and hasattr(block.content, "content"):
|
|
617
|
+
if isinstance(block.content.content, list):
|
|
618
|
+
for output_block in block.content.content:
|
|
619
|
+
if hasattr(output_block, "file_id"):
|
|
620
|
+
file_ids.append(output_block.file_id)
|
|
621
|
+
|
|
622
|
+
if file_ids:
|
|
623
|
+
if model_response.provider_data is None:
|
|
624
|
+
model_response.provider_data = {}
|
|
625
|
+
model_response.provider_data["file_ids"] = file_ids
|
|
626
|
+
|
|
627
|
+
return model_response
|
|
628
|
+
|
|
629
|
+
def _parse_provider_response_delta(
|
|
630
|
+
self,
|
|
631
|
+
response: Union[
|
|
632
|
+
ContentBlockStartEvent,
|
|
633
|
+
ContentBlockDeltaEvent,
|
|
634
|
+
ContentBlockStopEvent,
|
|
635
|
+
MessageStopEvent,
|
|
636
|
+
BetaRawContentBlockDeltaEvent,
|
|
637
|
+
],
|
|
638
|
+
) -> ModelResponse:
|
|
639
|
+
"""
|
|
640
|
+
Parse the Claude streaming response into ModelProviderResponse objects.
|
|
641
|
+
|
|
642
|
+
Args:
|
|
643
|
+
response: Raw response chunk from Anthropic
|
|
644
|
+
|
|
645
|
+
Returns:
|
|
646
|
+
ModelResponse: Iterator of parsed response data
|
|
647
|
+
"""
|
|
648
|
+
model_response = ModelResponse()
|
|
649
|
+
|
|
650
|
+
if isinstance(response, ContentBlockStartEvent):
|
|
651
|
+
if response.content_block.type == "redacted_reasoning_content":
|
|
652
|
+
model_response.redacted_reasoning_content = response.content_block.data
|
|
653
|
+
|
|
654
|
+
if isinstance(response, ContentBlockDeltaEvent):
|
|
655
|
+
# Handle text content
|
|
656
|
+
if response.delta.type == "text_delta":
|
|
657
|
+
model_response.content = response.delta.text
|
|
658
|
+
# Handle thinking content
|
|
659
|
+
elif response.delta.type == "thinking_delta":
|
|
660
|
+
model_response.reasoning_content = response.delta.thinking
|
|
661
|
+
elif response.delta.type == "signature_delta":
|
|
662
|
+
model_response.provider_data = {
|
|
663
|
+
"signature": response.delta.signature,
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
elif isinstance(response, ContentBlockStopEvent):
|
|
667
|
+
if response.content_block.type == "tool_use": # type: ignore
|
|
668
|
+
tool_use = response.content_block # type: ignore
|
|
669
|
+
tool_name = tool_use.name
|
|
670
|
+
tool_input = tool_use.input
|
|
671
|
+
|
|
672
|
+
function_def = {"name": tool_name}
|
|
673
|
+
if tool_input:
|
|
674
|
+
function_def["arguments"] = json.dumps(tool_input)
|
|
675
|
+
|
|
676
|
+
model_response.extra = model_response.extra or {}
|
|
677
|
+
|
|
678
|
+
model_response.tool_calls = [
|
|
679
|
+
{
|
|
680
|
+
"id": tool_use.id,
|
|
681
|
+
"type": "function",
|
|
682
|
+
"function": function_def,
|
|
683
|
+
}
|
|
684
|
+
]
|
|
685
|
+
|
|
686
|
+
# Capture citations from the final response
|
|
687
|
+
elif isinstance(response, MessageStopEvent):
|
|
688
|
+
model_response.content = ""
|
|
689
|
+
model_response.citations = Citations(raw=[], urls=[], documents=[])
|
|
690
|
+
for block in response.message.content: # type: ignore
|
|
691
|
+
citations = getattr(block, "citations", None)
|
|
692
|
+
if not citations:
|
|
693
|
+
continue
|
|
694
|
+
for citation in citations:
|
|
695
|
+
model_response.citations.raw.append(citation.model_dump()) # type: ignore
|
|
696
|
+
# Web search citations
|
|
697
|
+
if isinstance(citation, CitationsWebSearchResultLocation):
|
|
698
|
+
model_response.citations.urls.append(UrlCitation(url=citation.url, title=citation.cited_text)) # type: ignore
|
|
699
|
+
# Document citations
|
|
700
|
+
elif isinstance(citation, CitationPageLocation):
|
|
701
|
+
model_response.citations.documents.append( # type: ignore
|
|
702
|
+
DocumentCitation(document_title=citation.document_title, cited_text=citation.cited_text)
|
|
703
|
+
)
|
|
704
|
+
|
|
705
|
+
# Capture context management information if present
|
|
706
|
+
if self.context_management is not None and hasattr(response.message, "context_management"): # type: ignore
|
|
707
|
+
context_mgmt = response.message.context_management # type: ignore
|
|
708
|
+
if context_mgmt is not None:
|
|
709
|
+
model_response.provider_data = model_response.provider_data or {}
|
|
710
|
+
if hasattr(context_mgmt, "model_dump"):
|
|
711
|
+
model_response.provider_data["context_management"] = context_mgmt.model_dump()
|
|
712
|
+
else:
|
|
713
|
+
model_response.provider_data["context_management"] = context_mgmt
|
|
714
|
+
|
|
715
|
+
if hasattr(response, "message") and hasattr(response.message, "usage") and response.message.usage is not None: # type: ignore
|
|
716
|
+
model_response.response_usage = self._get_metrics(response.message.usage) # type: ignore
|
|
717
|
+
|
|
718
|
+
# Capture the Beta response
|
|
719
|
+
try:
|
|
720
|
+
if (
|
|
721
|
+
isinstance(response, BetaRawContentBlockDeltaEvent)
|
|
722
|
+
and isinstance(response.delta, BetaTextDelta)
|
|
723
|
+
and response.delta.text is not None
|
|
724
|
+
):
|
|
725
|
+
model_response.content = response.delta.text
|
|
726
|
+
except Exception as e:
|
|
727
|
+
log_error(f"Error parsing Beta response: {e}")
|
|
728
|
+
|
|
729
|
+
return model_response
|
|
730
|
+
|
|
731
|
+
def _get_metrics(self, response_usage: Union[Usage, MessageDeltaUsage, BetaUsage]) -> Metrics:
|
|
732
|
+
"""
|
|
733
|
+
Parse the given Anthropic-specific usage into an Agno Metrics object.
|
|
734
|
+
|
|
735
|
+
Args:
|
|
736
|
+
response_usage: Usage data from Anthropic
|
|
737
|
+
|
|
738
|
+
Returns:
|
|
739
|
+
Metrics: Parsed metrics data
|
|
740
|
+
"""
|
|
741
|
+
metrics = Metrics()
|
|
742
|
+
|
|
743
|
+
metrics.input_tokens = response_usage.input_tokens or 0
|
|
744
|
+
metrics.output_tokens = response_usage.output_tokens or 0
|
|
745
|
+
metrics.total_tokens = metrics.input_tokens + metrics.output_tokens
|
|
746
|
+
metrics.cache_read_tokens = response_usage.cache_read_input_tokens or 0
|
|
747
|
+
metrics.cache_write_tokens = response_usage.cache_creation_input_tokens or 0
|
|
748
|
+
|
|
749
|
+
# Anthropic-specific additional fields
|
|
750
|
+
if response_usage.server_tool_use:
|
|
751
|
+
metrics.provider_metrics = {"server_tool_use": response_usage.server_tool_use.model_dump()}
|
|
752
|
+
if isinstance(response_usage, Usage):
|
|
753
|
+
if response_usage.service_tier:
|
|
754
|
+
metrics.provider_metrics = metrics.provider_metrics or {}
|
|
755
|
+
metrics.provider_metrics["service_tier"] = response_usage.service_tier
|
|
756
|
+
|
|
757
|
+
return metrics
|