agno 0.1.2__py3-none-any.whl → 2.3.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 +44 -5
- agno/agent/agent.py +10531 -2975
- agno/api/agent.py +14 -53
- agno/api/api.py +7 -46
- agno/api/evals.py +22 -0
- agno/api/os.py +17 -0
- agno/api/routes.py +6 -25
- agno/api/schemas/__init__.py +9 -0
- agno/api/schemas/agent.py +6 -9
- agno/api/schemas/evals.py +16 -0
- agno/api/schemas/os.py +14 -0
- agno/api/schemas/team.py +10 -10
- agno/api/schemas/utils.py +21 -0
- agno/api/schemas/workflows.py +16 -0
- agno/api/settings.py +53 -0
- agno/api/team.py +22 -26
- 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/compression/__init__.py +3 -0
- agno/compression/manager.py +247 -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 +946 -0
- agno/db/dynamo/__init__.py +3 -0
- agno/db/dynamo/dynamo.py +2781 -0
- agno/db/dynamo/schemas.py +442 -0
- agno/db/dynamo/utils.py +743 -0
- agno/db/firestore/__init__.py +3 -0
- agno/db/firestore/firestore.py +2379 -0
- agno/db/firestore/schemas.py +181 -0
- agno/db/firestore/utils.py +376 -0
- agno/db/gcs_json/__init__.py +3 -0
- agno/db/gcs_json/gcs_json_db.py +1791 -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 +1312 -0
- agno/db/in_memory/utils.py +230 -0
- agno/db/json/__init__.py +3 -0
- agno/db/json/json_db.py +1777 -0
- agno/db/json/utils.py +230 -0
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +635 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/__init__.py +17 -0
- agno/db/mongo/async_mongo.py +2760 -0
- agno/db/mongo/mongo.py +2597 -0
- agno/db/mongo/schemas.py +119 -0
- agno/db/mongo/utils.py +276 -0
- agno/db/mysql/__init__.py +4 -0
- agno/db/mysql/async_mysql.py +2912 -0
- agno/db/mysql/mysql.py +2923 -0
- agno/db/mysql/schemas.py +186 -0
- agno/db/mysql/utils.py +488 -0
- agno/db/postgres/__init__.py +4 -0
- agno/db/postgres/async_postgres.py +2579 -0
- agno/db/postgres/postgres.py +2870 -0
- agno/db/postgres/schemas.py +187 -0
- agno/db/postgres/utils.py +442 -0
- agno/db/redis/__init__.py +3 -0
- agno/db/redis/redis.py +2141 -0
- agno/db/redis/schemas.py +159 -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 +34 -0
- agno/db/schemas/knowledge.py +40 -0
- agno/db/schemas/memory.py +61 -0
- agno/db/singlestore/__init__.py +3 -0
- agno/db/singlestore/schemas.py +179 -0
- agno/db/singlestore/singlestore.py +2877 -0
- agno/db/singlestore/utils.py +384 -0
- agno/db/sqlite/__init__.py +4 -0
- agno/db/sqlite/async_sqlite.py +2911 -0
- agno/db/sqlite/schemas.py +181 -0
- agno/db/sqlite/sqlite.py +2908 -0
- agno/db/sqlite/utils.py +429 -0
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +334 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1908 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +118 -0
- agno/eval/__init__.py +24 -0
- agno/eval/accuracy.py +666 -276
- agno/eval/agent_as_judge.py +861 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +779 -0
- agno/eval/reliability.py +241 -62
- agno/eval/utils.py +120 -0
- agno/exceptions.py +143 -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/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/__init__.py +3 -0
- agno/integrations/discord/client.py +203 -0
- agno/knowledge/__init__.py +5 -1
- agno/{document → knowledge}/chunking/agentic.py +22 -14
- agno/{document → knowledge}/chunking/document.py +2 -2
- agno/{document → knowledge}/chunking/fixed.py +7 -6
- agno/knowledge/chunking/markdown.py +151 -0
- agno/{document → knowledge}/chunking/recursive.py +15 -3
- agno/knowledge/chunking/row.py +39 -0
- agno/knowledge/chunking/semantic.py +91 -0
- agno/knowledge/chunking/strategy.py +165 -0
- agno/knowledge/content.py +74 -0
- agno/knowledge/document/__init__.py +5 -0
- agno/{document → knowledge/document}/base.py +12 -2
- agno/knowledge/embedder/__init__.py +5 -0
- agno/knowledge/embedder/aws_bedrock.py +343 -0
- agno/knowledge/embedder/azure_openai.py +210 -0
- agno/{embedder → knowledge/embedder}/base.py +8 -0
- agno/knowledge/embedder/cohere.py +323 -0
- agno/knowledge/embedder/fastembed.py +62 -0
- agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
- 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/{embedder → knowledge/embedder}/together.py +1 -1
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +165 -0
- agno/knowledge/knowledge.py +3006 -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 +164 -0
- agno/knowledge/reader/docx_reader.py +82 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
- agno/knowledge/reader/firecrawl_reader.py +201 -0
- agno/knowledge/reader/json_reader.py +88 -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 +193 -0
- agno/knowledge/reader/text_reader.py +127 -0
- agno/knowledge/reader/web_search_reader.py +325 -0
- agno/knowledge/reader/website_reader.py +455 -0
- agno/knowledge/reader/wikipedia_reader.py +91 -0
- agno/knowledge/reader/youtube_reader.py +78 -0
- agno/knowledge/remote_content/remote_content.py +88 -0
- agno/knowledge/reranker/__init__.py +3 -0
- agno/{reranker → knowledge/reranker}/base.py +1 -1
- agno/{reranker → knowledge/reranker}/cohere.py +2 -2
- 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 +234 -0
- agno/media.py +439 -95
- agno/memory/__init__.py +16 -3
- agno/memory/manager.py +1474 -123
- agno/memory/strategies/__init__.py +15 -0
- agno/memory/strategies/base.py +66 -0
- agno/memory/strategies/summarize.py +196 -0
- agno/memory/strategies/types.py +37 -0
- agno/models/aimlapi/__init__.py +5 -0
- agno/models/aimlapi/aimlapi.py +62 -0
- agno/models/anthropic/__init__.py +4 -0
- agno/models/anthropic/claude.py +960 -496
- agno/models/aws/__init__.py +15 -0
- agno/models/aws/bedrock.py +686 -451
- agno/models/aws/claude.py +190 -183
- agno/models/azure/__init__.py +18 -1
- agno/models/azure/ai_foundry.py +489 -0
- agno/models/azure/openai_chat.py +89 -40
- agno/models/base.py +2477 -550
- agno/models/cerebras/__init__.py +12 -0
- agno/models/cerebras/cerebras.py +565 -0
- agno/models/cerebras/cerebras_openai.py +131 -0
- agno/models/cohere/__init__.py +4 -0
- agno/models/cohere/chat.py +306 -492
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +74 -0
- agno/models/dashscope/__init__.py +5 -0
- agno/models/dashscope/dashscope.py +90 -0
- agno/models/deepinfra/__init__.py +5 -0
- agno/models/deepinfra/deepinfra.py +45 -0
- agno/models/deepseek/__init__.py +4 -0
- agno/models/deepseek/deepseek.py +110 -9
- agno/models/fireworks/__init__.py +4 -0
- agno/models/fireworks/fireworks.py +19 -22
- agno/models/google/__init__.py +3 -7
- agno/models/google/gemini.py +1717 -662
- agno/models/google/utils.py +22 -0
- agno/models/groq/__init__.py +4 -0
- agno/models/groq/groq.py +391 -666
- agno/models/huggingface/__init__.py +4 -0
- agno/models/huggingface/huggingface.py +266 -538
- agno/models/ibm/__init__.py +5 -0
- agno/models/ibm/watsonx.py +432 -0
- agno/models/internlm/__init__.py +3 -0
- agno/models/internlm/internlm.py +20 -3
- agno/models/langdb/__init__.py +1 -0
- agno/models/langdb/langdb.py +60 -0
- agno/models/litellm/__init__.py +14 -0
- agno/models/litellm/chat.py +503 -0
- agno/models/litellm/litellm_openai.py +42 -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 +361 -39
- agno/models/meta/__init__.py +12 -0
- agno/models/meta/llama.py +502 -0
- agno/models/meta/llama_openai.py +79 -0
- agno/models/metrics.py +120 -0
- agno/models/mistral/__init__.py +4 -0
- agno/models/mistral/mistral.py +293 -393
- agno/models/nebius/__init__.py +3 -0
- agno/models/nebius/nebius.py +53 -0
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/__init__.py +4 -0
- agno/models/nvidia/nvidia.py +22 -3
- agno/models/ollama/__init__.py +4 -2
- agno/models/ollama/chat.py +257 -492
- agno/models/openai/__init__.py +7 -0
- agno/models/openai/chat.py +725 -770
- agno/models/openai/like.py +16 -2
- agno/models/openai/responses.py +1121 -0
- agno/models/openrouter/__init__.py +4 -0
- agno/models/openrouter/openrouter.py +62 -5
- agno/models/perplexity/__init__.py +5 -0
- agno/models/perplexity/perplexity.py +203 -0
- agno/models/portkey/__init__.py +3 -0
- agno/models/portkey/portkey.py +82 -0
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +69 -0
- agno/models/response.py +177 -7
- agno/models/sambanova/__init__.py +4 -0
- agno/models/sambanova/sambanova.py +23 -4
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +42 -0
- agno/models/together/__init__.py +4 -0
- agno/models/together/together.py +21 -164
- agno/models/utils.py +266 -0
- agno/models/vercel/__init__.py +3 -0
- agno/models/vercel/v0.py +43 -0
- agno/models/vertexai/__init__.py +0 -1
- agno/models/vertexai/claude.py +190 -0
- agno/models/vllm/__init__.py +3 -0
- agno/models/vllm/vllm.py +83 -0
- agno/models/xai/__init__.py +2 -0
- agno/models/xai/xai.py +111 -7
- agno/os/__init__.py +3 -0
- agno/os/app.py +1027 -0
- agno/os/auth.py +244 -0
- agno/os/config.py +126 -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 +249 -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 +147 -0
- agno/os/interfaces/agui/utils.py +574 -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 +210 -0
- agno/os/interfaces/whatsapp/security.py +55 -0
- agno/os/interfaces/whatsapp/whatsapp.py +36 -0
- agno/os/mcp.py +293 -0
- agno/os/middleware/__init__.py +9 -0
- agno/os/middleware/jwt.py +797 -0
- agno/os/router.py +258 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +599 -0
- agno/os/routers/agents/schema.py +261 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +450 -0
- agno/os/routers/evals/schemas.py +174 -0
- agno/os/routers/evals/utils.py +231 -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 +1008 -0
- agno/os/routers/knowledge/schemas.py +178 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +661 -0
- agno/os/routers/memory/schemas.py +88 -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/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +512 -0
- agno/os/routers/teams/schema.py +257 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +499 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +624 -0
- agno/os/routers/workflows/schema.py +75 -0
- agno/os/schema.py +534 -0
- agno/os/scopes.py +469 -0
- agno/{playground → os}/settings.py +7 -15
- agno/os/utils.py +973 -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 +24 -1
- agno/reasoning/ollama.py +67 -0
- agno/reasoning/openai.py +86 -0
- agno/reasoning/step.py +2 -1
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +822 -0
- agno/run/base.py +247 -0
- agno/run/cancel.py +81 -0
- agno/run/requirement.py +181 -0
- agno/run/team.py +767 -0
- agno/run/workflow.py +708 -0
- agno/session/__init__.py +10 -0
- agno/session/agent.py +260 -0
- agno/session/summary.py +265 -0
- agno/session/team.py +342 -0
- agno/session/workflow.py +501 -0
- agno/table.py +10 -0
- agno/team/__init__.py +37 -0
- agno/team/team.py +9536 -0
- agno/tools/__init__.py +7 -0
- agno/tools/agentql.py +120 -0
- agno/tools/airflow.py +22 -12
- agno/tools/api.py +122 -0
- agno/tools/apify.py +276 -83
- agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
- agno/tools/aws_lambda.py +28 -7
- agno/tools/aws_ses.py +66 -0
- agno/tools/baidusearch.py +11 -4
- 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 +32 -23
- agno/tools/calculator.py +24 -37
- agno/tools/cartesia.py +187 -0
- agno/tools/{clickup_tool.py → clickup.py} +17 -28
- agno/tools/confluence.py +91 -26
- agno/tools/crawl4ai.py +139 -43
- agno/tools/csv_toolkit.py +28 -22
- agno/tools/dalle.py +36 -22
- agno/tools/daytona.py +475 -0
- agno/tools/decorator.py +169 -14
- agno/tools/desi_vocal.py +23 -11
- agno/tools/discord.py +32 -29
- agno/tools/docker.py +716 -0
- agno/tools/duckdb.py +76 -81
- agno/tools/duckduckgo.py +43 -40
- agno/tools/e2b.py +703 -0
- agno/tools/eleven_labs.py +65 -54
- agno/tools/email.py +13 -5
- agno/tools/evm.py +129 -0
- agno/tools/exa.py +324 -42
- agno/tools/fal.py +39 -35
- agno/tools/file.py +196 -30
- agno/tools/file_generation.py +356 -0
- agno/tools/financial_datasets.py +288 -0
- agno/tools/firecrawl.py +108 -33
- agno/tools/function.py +960 -122
- agno/tools/giphy.py +34 -12
- agno/tools/github.py +1294 -97
- agno/tools/gmail.py +922 -0
- agno/tools/google_bigquery.py +117 -0
- agno/tools/google_drive.py +271 -0
- agno/tools/google_maps.py +253 -0
- agno/tools/googlecalendar.py +607 -107
- agno/tools/googlesheets.py +377 -0
- agno/tools/hackernews.py +20 -12
- agno/tools/jina.py +24 -14
- agno/tools/jira.py +48 -19
- agno/tools/knowledge.py +218 -0
- agno/tools/linear.py +82 -43
- agno/tools/linkup.py +58 -0
- agno/tools/local_file_system.py +15 -7
- agno/tools/lumalab.py +41 -26
- 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/memory.py +419 -0
- agno/tools/mlx_transcribe.py +11 -9
- 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 +163 -82
- agno/tools/moviepy_video.py +18 -13
- agno/tools/nano_banana.py +151 -0
- agno/tools/neo4j.py +134 -0
- agno/tools/newspaper.py +15 -4
- agno/tools/newspaper4k.py +19 -6
- agno/tools/notion.py +204 -0
- agno/tools/openai.py +181 -17
- agno/tools/openbb.py +27 -20
- agno/tools/opencv.py +321 -0
- agno/tools/openweather.py +233 -0
- agno/tools/oxylabs.py +385 -0
- agno/tools/pandas.py +25 -15
- agno/tools/parallel.py +314 -0
- agno/tools/postgres.py +238 -185
- agno/tools/pubmed.py +125 -13
- agno/tools/python.py +48 -35
- agno/tools/reasoning.py +283 -0
- agno/tools/reddit.py +207 -29
- agno/tools/redshift.py +406 -0
- agno/tools/replicate.py +69 -26
- agno/tools/resend.py +11 -6
- agno/tools/scrapegraph.py +179 -19
- agno/tools/searxng.py +23 -31
- agno/tools/serpapi.py +15 -10
- agno/tools/serper.py +255 -0
- agno/tools/shell.py +23 -12
- agno/tools/shopify.py +1519 -0
- agno/tools/slack.py +56 -14
- agno/tools/sleep.py +8 -6
- agno/tools/spider.py +35 -11
- agno/tools/spotify.py +919 -0
- agno/tools/sql.py +34 -19
- agno/tools/tavily.py +158 -8
- agno/tools/telegram.py +18 -8
- agno/tools/todoist.py +218 -0
- agno/tools/toolkit.py +134 -9
- agno/tools/trafilatura.py +388 -0
- agno/tools/trello.py +25 -28
- agno/tools/twilio.py +18 -9
- 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 +23 -19
- agno/tools/webtools.py +45 -0
- agno/tools/whatsapp.py +286 -0
- agno/tools/wikipedia.py +28 -19
- agno/tools/workflow.py +285 -0
- agno/tools/{twitter.py → x.py} +142 -46
- agno/tools/yfinance.py +41 -39
- agno/tools/youtube.py +34 -17
- agno/tools/zendesk.py +15 -5
- agno/tools/zep.py +454 -0
- agno/tools/zoom.py +86 -37
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +157 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +111 -0
- agno/utils/agent.py +938 -0
- agno/utils/audio.py +37 -1
- agno/utils/certs.py +27 -0
- agno/utils/code_execution.py +11 -0
- agno/utils/common.py +103 -20
- agno/utils/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +700 -0
- agno/utils/functions.py +107 -37
- agno/utils/gemini.py +426 -0
- agno/utils/hooks.py +171 -0
- agno/utils/http.py +185 -0
- agno/utils/json_schema.py +159 -37
- agno/utils/knowledge.py +36 -0
- agno/utils/location.py +19 -0
- agno/utils/log.py +221 -8
- agno/utils/mcp.py +214 -0
- agno/utils/media.py +335 -14
- agno/utils/merge_dict.py +22 -1
- agno/utils/message.py +77 -2
- agno/utils/models/ai_foundry.py +50 -0
- agno/utils/models/claude.py +373 -0
- agno/utils/models/cohere.py +94 -0
- agno/utils/models/llama.py +85 -0
- agno/utils/models/mistral.py +100 -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 +1 -1
- agno/utils/pprint.py +124 -8
- agno/utils/print_response/agent.py +930 -0
- agno/utils/print_response/team.py +1914 -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/serialize.py +32 -0
- agno/utils/shell.py +4 -4
- agno/utils/streamlit.py +487 -0
- agno/utils/string.py +204 -51
- agno/utils/team.py +139 -0
- agno/utils/timer.py +9 -2
- agno/utils/tokens.py +657 -0
- agno/utils/tools.py +19 -1
- agno/utils/whatsapp.py +305 -0
- agno/utils/yaml_io.py +3 -3
- agno/vectordb/__init__.py +2 -0
- agno/vectordb/base.py +87 -9
- agno/vectordb/cassandra/__init__.py +5 -1
- agno/vectordb/cassandra/cassandra.py +383 -27
- agno/vectordb/chroma/__init__.py +4 -0
- agno/vectordb/chroma/chromadb.py +748 -83
- agno/vectordb/clickhouse/__init__.py +7 -1
- agno/vectordb/clickhouse/clickhousedb.py +554 -53
- agno/vectordb/couchbase/__init__.py +3 -0
- agno/vectordb/couchbase/couchbase.py +1446 -0
- agno/vectordb/lancedb/__init__.py +5 -0
- agno/vectordb/lancedb/lance_db.py +730 -98
- 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 +3 -0
- agno/vectordb/milvus/milvus.py +966 -78
- agno/vectordb/mongodb/__init__.py +9 -1
- agno/vectordb/mongodb/mongodb.py +1175 -172
- agno/vectordb/pgvector/__init__.py +8 -0
- agno/vectordb/pgvector/pgvector.py +599 -115
- agno/vectordb/pineconedb/__init__.py +5 -1
- agno/vectordb/pineconedb/pineconedb.py +406 -43
- agno/vectordb/qdrant/__init__.py +4 -0
- agno/vectordb/qdrant/qdrant.py +914 -61
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +682 -0
- agno/vectordb/singlestore/__init__.py +8 -1
- agno/vectordb/singlestore/singlestore.py +771 -0
- agno/vectordb/surrealdb/__init__.py +3 -0
- agno/vectordb/surrealdb/surrealdb.py +663 -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 +1009 -0
- agno/workflow/__init__.py +23 -1
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +759 -0
- agno/workflow/loop.py +756 -0
- agno/workflow/parallel.py +853 -0
- agno/workflow/router.py +723 -0
- agno/workflow/step.py +1564 -0
- agno/workflow/steps.py +613 -0
- agno/workflow/types.py +556 -0
- agno/workflow/workflow.py +4327 -514
- agno-2.3.13.dist-info/METADATA +639 -0
- agno-2.3.13.dist-info/RECORD +613 -0
- {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
- agno-2.3.13.dist-info/licenses/LICENSE +201 -0
- agno/api/playground.py +0 -91
- agno/api/schemas/playground.py +0 -22
- agno/api/schemas/user.py +0 -22
- agno/api/schemas/workspace.py +0 -46
- agno/api/user.py +0 -160
- agno/api/workspace.py +0 -151
- agno/cli/auth_server.py +0 -118
- agno/cli/config.py +0 -275
- agno/cli/console.py +0 -88
- agno/cli/credentials.py +0 -23
- agno/cli/entrypoint.py +0 -571
- agno/cli/operator.py +0 -355
- agno/cli/settings.py +0 -85
- agno/cli/ws/ws_cli.py +0 -817
- agno/constants.py +0 -13
- agno/document/__init__.py +0 -1
- agno/document/chunking/semantic.py +0 -47
- agno/document/chunking/strategy.py +0 -31
- agno/document/reader/__init__.py +0 -1
- agno/document/reader/arxiv_reader.py +0 -41
- agno/document/reader/base.py +0 -22
- agno/document/reader/csv_reader.py +0 -84
- agno/document/reader/docx_reader.py +0 -46
- agno/document/reader/firecrawl_reader.py +0 -99
- agno/document/reader/json_reader.py +0 -43
- agno/document/reader/pdf_reader.py +0 -219
- agno/document/reader/s3/pdf_reader.py +0 -46
- agno/document/reader/s3/text_reader.py +0 -51
- agno/document/reader/text_reader.py +0 -41
- agno/document/reader/website_reader.py +0 -175
- agno/document/reader/youtube_reader.py +0 -50
- agno/embedder/__init__.py +0 -1
- agno/embedder/azure_openai.py +0 -86
- agno/embedder/cohere.py +0 -72
- agno/embedder/fastembed.py +0 -37
- agno/embedder/google.py +0 -73
- agno/embedder/huggingface.py +0 -54
- agno/embedder/mistral.py +0 -80
- agno/embedder/ollama.py +0 -57
- agno/embedder/openai.py +0 -74
- agno/embedder/sentence_transformer.py +0 -38
- agno/embedder/voyageai.py +0 -64
- agno/eval/perf.py +0 -201
- agno/file/__init__.py +0 -1
- agno/file/file.py +0 -16
- agno/file/local/csv.py +0 -32
- agno/file/local/txt.py +0 -19
- agno/infra/app.py +0 -240
- agno/infra/base.py +0 -144
- agno/infra/context.py +0 -20
- agno/infra/db_app.py +0 -52
- agno/infra/resource.py +0 -205
- agno/infra/resources.py +0 -55
- agno/knowledge/agent.py +0 -230
- agno/knowledge/arxiv.py +0 -22
- agno/knowledge/combined.py +0 -22
- agno/knowledge/csv.py +0 -28
- agno/knowledge/csv_url.py +0 -19
- agno/knowledge/document.py +0 -20
- agno/knowledge/docx.py +0 -30
- agno/knowledge/json.py +0 -28
- agno/knowledge/langchain.py +0 -71
- agno/knowledge/llamaindex.py +0 -66
- agno/knowledge/pdf.py +0 -28
- agno/knowledge/pdf_url.py +0 -26
- agno/knowledge/s3/base.py +0 -60
- agno/knowledge/s3/pdf.py +0 -21
- agno/knowledge/s3/text.py +0 -23
- agno/knowledge/text.py +0 -30
- agno/knowledge/website.py +0 -88
- agno/knowledge/wikipedia.py +0 -31
- agno/knowledge/youtube.py +0 -22
- agno/memory/agent.py +0 -392
- agno/memory/classifier.py +0 -104
- agno/memory/db/__init__.py +0 -1
- agno/memory/db/base.py +0 -42
- agno/memory/db/mongodb.py +0 -189
- agno/memory/db/postgres.py +0 -203
- agno/memory/db/sqlite.py +0 -193
- agno/memory/memory.py +0 -15
- agno/memory/row.py +0 -36
- agno/memory/summarizer.py +0 -192
- agno/memory/summary.py +0 -19
- agno/memory/workflow.py +0 -38
- agno/models/google/gemini_openai.py +0 -26
- agno/models/ollama/hermes.py +0 -221
- agno/models/ollama/tools.py +0 -362
- agno/models/vertexai/gemini.py +0 -595
- agno/playground/__init__.py +0 -3
- agno/playground/async_router.py +0 -421
- agno/playground/deploy.py +0 -249
- agno/playground/operator.py +0 -92
- agno/playground/playground.py +0 -91
- agno/playground/schemas.py +0 -76
- agno/playground/serve.py +0 -55
- agno/playground/sync_router.py +0 -405
- agno/reasoning/agent.py +0 -68
- agno/run/response.py +0 -112
- agno/storage/agent/__init__.py +0 -0
- agno/storage/agent/base.py +0 -38
- agno/storage/agent/dynamodb.py +0 -350
- agno/storage/agent/json.py +0 -92
- agno/storage/agent/mongodb.py +0 -228
- agno/storage/agent/postgres.py +0 -367
- agno/storage/agent/session.py +0 -79
- agno/storage/agent/singlestore.py +0 -303
- agno/storage/agent/sqlite.py +0 -357
- agno/storage/agent/yaml.py +0 -93
- agno/storage/workflow/__init__.py +0 -0
- agno/storage/workflow/base.py +0 -40
- agno/storage/workflow/mongodb.py +0 -233
- agno/storage/workflow/postgres.py +0 -366
- agno/storage/workflow/session.py +0 -60
- agno/storage/workflow/sqlite.py +0 -359
- agno/tools/googlesearch.py +0 -88
- agno/utils/defaults.py +0 -57
- agno/utils/filesystem.py +0 -39
- agno/utils/git.py +0 -52
- agno/utils/json_io.py +0 -30
- agno/utils/load_env.py +0 -19
- agno/utils/py_io.py +0 -19
- agno/utils/pyproject.py +0 -18
- agno/utils/resource_filter.py +0 -31
- agno/vectordb/singlestore/s2vectordb.py +0 -390
- agno/vectordb/singlestore/s2vectordb2.py +0 -355
- agno/workspace/__init__.py +0 -0
- agno/workspace/config.py +0 -325
- agno/workspace/enums.py +0 -6
- agno/workspace/helpers.py +0 -48
- agno/workspace/operator.py +0 -758
- agno/workspace/settings.py +0 -63
- agno-0.1.2.dist-info/LICENSE +0 -375
- agno-0.1.2.dist-info/METADATA +0 -502
- agno-0.1.2.dist-info/RECORD +0 -352
- agno-0.1.2.dist-info/entry_points.txt +0 -3
- /agno/{cli → db/migrations}/__init__.py +0 -0
- /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
- /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
- /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
- /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
- /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
- /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
- /agno/{reranker → utils/models}/__init__.py +0 -0
- /agno/{storage → utils/print_response}/__init__.py +0 -0
- {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
agno/models/cohere/chat.py
CHANGED
|
@@ -1,41 +1,37 @@
|
|
|
1
|
-
import json
|
|
2
1
|
from dataclasses import dataclass
|
|
3
2
|
from os import getenv
|
|
4
|
-
from typing import Any, Dict, Iterator, List, Optional, Tuple
|
|
3
|
+
from typing import Any, AsyncIterator, Dict, Iterator, List, Optional, Tuple, Type, Union
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
import httpx
|
|
6
|
+
from pydantic import BaseModel
|
|
7
|
+
|
|
8
|
+
from agno.exceptions import ModelProviderError
|
|
9
|
+
from agno.models.base import Model
|
|
7
10
|
from agno.models.message import Message
|
|
8
|
-
from agno.models.
|
|
9
|
-
from agno.
|
|
10
|
-
from agno.
|
|
11
|
-
from agno.utils.
|
|
12
|
-
from agno.utils.
|
|
11
|
+
from agno.models.metrics import Metrics
|
|
12
|
+
from agno.models.response import ModelResponse
|
|
13
|
+
from agno.run.agent import RunOutput
|
|
14
|
+
from agno.utils.http import get_default_async_client, get_default_sync_client
|
|
15
|
+
from agno.utils.log import log_debug, log_error, log_warning
|
|
16
|
+
from agno.utils.models.cohere import format_messages
|
|
13
17
|
|
|
14
18
|
try:
|
|
15
|
-
from cohere import
|
|
16
|
-
from cohere
|
|
17
|
-
from cohere.types.
|
|
18
|
-
from cohere.types.
|
|
19
|
-
|
|
20
|
-
StreamedChatResponse,
|
|
21
|
-
StreamEndStreamedChatResponse,
|
|
22
|
-
StreamStartStreamedChatResponse,
|
|
23
|
-
TextGenerationStreamedChatResponse,
|
|
24
|
-
ToolCallsChunkStreamedChatResponse,
|
|
25
|
-
ToolCallsGenerationStreamedChatResponse,
|
|
26
|
-
)
|
|
27
|
-
from cohere.types.tool import Tool as CohereTool
|
|
28
|
-
from cohere.types.tool_call import ToolCall
|
|
29
|
-
from cohere.types.tool_parameter_definitions_value import (
|
|
30
|
-
ToolParameterDefinitionsValue,
|
|
31
|
-
)
|
|
32
|
-
from cohere.types.tool_result import ToolResult
|
|
33
|
-
except (ModuleNotFoundError, ImportError):
|
|
19
|
+
from cohere import AsyncClientV2 as CohereAsyncClient
|
|
20
|
+
from cohere import ClientV2 as CohereClient
|
|
21
|
+
from cohere.v2.types.v2chat_response import V2ChatResponse
|
|
22
|
+
from cohere.v2.types.v2chat_stream_response import V2ChatStreamResponse
|
|
23
|
+
except ImportError:
|
|
34
24
|
raise ImportError("`cohere` not installed. Please install using `pip install cohere`")
|
|
35
25
|
|
|
36
26
|
|
|
37
27
|
@dataclass
|
|
38
28
|
class Cohere(Model):
|
|
29
|
+
"""
|
|
30
|
+
A class representing the Cohere model.
|
|
31
|
+
|
|
32
|
+
For more information, see: https://docs.cohere.com/docs/chat-api
|
|
33
|
+
"""
|
|
34
|
+
|
|
39
35
|
id: str = "command-r-plus"
|
|
40
36
|
name: str = "cohere"
|
|
41
37
|
provider: str = "Cohere"
|
|
@@ -45,565 +41,383 @@ class Cohere(Model):
|
|
|
45
41
|
max_tokens: Optional[int] = None
|
|
46
42
|
top_k: Optional[int] = None
|
|
47
43
|
top_p: Optional[float] = None
|
|
44
|
+
seed: Optional[int] = None
|
|
48
45
|
frequency_penalty: Optional[float] = None
|
|
49
46
|
presence_penalty: Optional[float] = None
|
|
47
|
+
logprobs: Optional[bool] = None
|
|
50
48
|
request_params: Optional[Dict[str, Any]] = None
|
|
49
|
+
strict_tools: bool = False
|
|
51
50
|
# Add chat history to the cohere messages instead of using the conversation_id
|
|
52
51
|
add_chat_history: bool = False
|
|
53
52
|
# -*- Client parameters
|
|
54
53
|
api_key: Optional[str] = None
|
|
55
54
|
client_params: Optional[Dict[str, Any]] = None
|
|
55
|
+
http_client: Optional[Union[httpx.Client, httpx.AsyncClient]] = None
|
|
56
56
|
# -*- Provide the Cohere client manually
|
|
57
|
-
|
|
57
|
+
client: Optional[CohereClient] = None
|
|
58
|
+
async_client: Optional[CohereAsyncClient] = None
|
|
58
59
|
|
|
59
60
|
def get_client(self) -> CohereClient:
|
|
60
|
-
if self.
|
|
61
|
-
return self.
|
|
61
|
+
if self.client:
|
|
62
|
+
return self.client
|
|
62
63
|
|
|
63
64
|
_client_params: Dict[str, Any] = {}
|
|
64
65
|
|
|
65
66
|
self.api_key = self.api_key or getenv("CO_API_KEY")
|
|
66
67
|
if not self.api_key:
|
|
67
|
-
|
|
68
|
+
log_error("CO_API_KEY not set. Please set the CO_API_KEY environment variable.")
|
|
69
|
+
|
|
70
|
+
_client_params["api_key"] = self.api_key
|
|
71
|
+
|
|
72
|
+
if self.http_client:
|
|
73
|
+
if isinstance(self.http_client, httpx.Client):
|
|
74
|
+
_client_params["httpx_client"] = self.http_client
|
|
75
|
+
else:
|
|
76
|
+
log_warning("http_client is not an instance of httpx.Client. Using default global httpx.Client.")
|
|
77
|
+
# Use global sync client when user http_client is invalid
|
|
78
|
+
_client_params["httpx_client"] = get_default_sync_client()
|
|
79
|
+
else:
|
|
80
|
+
# Use global sync client when no custom http_client is provided
|
|
81
|
+
_client_params["httpx_client"] = get_default_sync_client()
|
|
82
|
+
|
|
83
|
+
self.client = CohereClient(**_client_params)
|
|
84
|
+
return self.client # type: ignore
|
|
68
85
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
86
|
+
def get_async_client(self) -> CohereAsyncClient:
|
|
87
|
+
if self.async_client:
|
|
88
|
+
return self.async_client
|
|
72
89
|
|
|
73
|
-
|
|
74
|
-
|
|
90
|
+
_client_params: Dict[str, Any] = {}
|
|
91
|
+
|
|
92
|
+
self.api_key = self.api_key or getenv("CO_API_KEY")
|
|
93
|
+
|
|
94
|
+
if not self.api_key:
|
|
95
|
+
raise ModelProviderError(
|
|
96
|
+
message="CO_API_KEY not set. Please set the CO_API_KEY environment variable.",
|
|
97
|
+
model_name=self.name,
|
|
98
|
+
model_id=self.id,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
_client_params["api_key"] = self.api_key
|
|
102
|
+
|
|
103
|
+
if self.http_client:
|
|
104
|
+
if isinstance(self.http_client, httpx.AsyncClient):
|
|
105
|
+
_client_params["httpx_client"] = self.http_client
|
|
106
|
+
else:
|
|
107
|
+
log_warning(
|
|
108
|
+
"http_client is not an instance of httpx.AsyncClient. Using default global httpx.AsyncClient."
|
|
109
|
+
)
|
|
110
|
+
# Use global async client when user http_client is invalid
|
|
111
|
+
_client_params["httpx_client"] = get_default_async_client()
|
|
112
|
+
else:
|
|
113
|
+
# Use global async client when no custom http_client is provided
|
|
114
|
+
_client_params["httpx_client"] = get_default_async_client()
|
|
115
|
+
self.async_client = CohereAsyncClient(**_client_params)
|
|
116
|
+
return self.async_client # type: ignore
|
|
117
|
+
|
|
118
|
+
def get_request_params(
|
|
119
|
+
self,
|
|
120
|
+
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
121
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
122
|
+
) -> Dict[str, Any]:
|
|
75
123
|
_request_params: Dict[str, Any] = {}
|
|
76
|
-
if self.session_id is not None and not self.add_chat_history:
|
|
77
|
-
_request_params["conversation_id"] = self.session_id
|
|
78
124
|
if self.temperature:
|
|
79
125
|
_request_params["temperature"] = self.temperature
|
|
80
126
|
if self.max_tokens:
|
|
81
127
|
_request_params["max_tokens"] = self.max_tokens
|
|
82
128
|
if self.top_k:
|
|
83
|
-
_request_params["
|
|
129
|
+
_request_params["k"] = self.top_k
|
|
84
130
|
if self.top_p:
|
|
85
|
-
_request_params["
|
|
131
|
+
_request_params["p"] = self.top_p
|
|
132
|
+
if self.seed:
|
|
133
|
+
_request_params["seed"] = self.seed
|
|
134
|
+
if self.logprobs:
|
|
135
|
+
_request_params["logprobs"] = self.logprobs
|
|
86
136
|
if self.frequency_penalty:
|
|
87
137
|
_request_params["frequency_penalty"] = self.frequency_penalty
|
|
88
138
|
if self.presence_penalty:
|
|
89
139
|
_request_params["presence_penalty"] = self.presence_penalty
|
|
90
|
-
if self.request_params:
|
|
91
|
-
_request_params.update(self.request_params)
|
|
92
|
-
return _request_params
|
|
93
140
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
required="null" not in param_info["type"],
|
|
113
|
-
)
|
|
114
|
-
for param_name, param_info in function.parameters.get("properties", {}).items()
|
|
115
|
-
},
|
|
116
|
-
)
|
|
117
|
-
for f_name, function in self._functions.items()
|
|
118
|
-
]
|
|
119
|
-
|
|
120
|
-
def _prepare_for_invoke(
|
|
121
|
-
self, messages: List[Message], tool_results: Optional[List[ToolResult]] = None
|
|
122
|
-
) -> Tuple[str, Dict[str, Any]]:
|
|
123
|
-
api_kwargs: Dict[str, Any] = self.request_kwargs
|
|
124
|
-
chat_message: str = ""
|
|
125
|
-
|
|
126
|
-
if self.add_chat_history:
|
|
127
|
-
logger.debug("Providing chat_history to cohere")
|
|
128
|
-
chat_history: List = []
|
|
129
|
-
for m in messages:
|
|
130
|
-
if m.role == "system" and "preamble" not in api_kwargs:
|
|
131
|
-
api_kwargs["preamble"] = m.content
|
|
132
|
-
elif m.role == "user":
|
|
133
|
-
# Update the chat_message to the new user message
|
|
134
|
-
chat_message = m.get_content_string()
|
|
135
|
-
chat_history.append({"role": "USER", "message": chat_message})
|
|
141
|
+
if response_format:
|
|
142
|
+
_request_params["response_format"] = response_format
|
|
143
|
+
|
|
144
|
+
# Format tools
|
|
145
|
+
if tools is not None and len(tools) > 0:
|
|
146
|
+
formatted_tools = []
|
|
147
|
+
for tool in tools:
|
|
148
|
+
if tool.get("type") == "function" and "function" in tool:
|
|
149
|
+
# Extract only the fields that Cohere supports
|
|
150
|
+
filtered_tool = {
|
|
151
|
+
"type": "function",
|
|
152
|
+
"function": {
|
|
153
|
+
"name": tool["function"]["name"],
|
|
154
|
+
"description": tool["function"]["description"],
|
|
155
|
+
"parameters": tool["function"]["parameters"],
|
|
156
|
+
},
|
|
157
|
+
}
|
|
158
|
+
formatted_tools.append(filtered_tool)
|
|
136
159
|
else:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if m.role == "user":
|
|
150
|
-
chat_message = m.get_content_string()
|
|
151
|
-
break
|
|
152
|
-
|
|
153
|
-
if self.tools:
|
|
154
|
-
api_kwargs["tools"] = self._get_tools()
|
|
160
|
+
# For non-function tools, pass them through as-is
|
|
161
|
+
formatted_tools.append(tool)
|
|
162
|
+
|
|
163
|
+
_request_params["tools"] = formatted_tools
|
|
164
|
+
# Fix optional parameters where the "type" is [type, null]
|
|
165
|
+
for tool in _request_params["tools"]: # type: ignore
|
|
166
|
+
if "parameters" in tool["function"] and "properties" in tool["function"]["parameters"]: # type: ignore
|
|
167
|
+
params = tool["function"]["parameters"]
|
|
168
|
+
# Cohere requires at least one required parameter, so if unset, set it to all parameters
|
|
169
|
+
if len(params.get("required", [])) == 0:
|
|
170
|
+
params["required"] = list(params["properties"].keys())
|
|
171
|
+
_request_params["strict_tools"] = self.strict_tools
|
|
155
172
|
|
|
156
|
-
if
|
|
157
|
-
|
|
173
|
+
if self.request_params:
|
|
174
|
+
_request_params.update(self.request_params)
|
|
158
175
|
|
|
159
|
-
|
|
176
|
+
if _request_params:
|
|
177
|
+
log_debug(f"Calling {self.provider} with request parameters: {_request_params}", log_level=2)
|
|
178
|
+
return _request_params
|
|
160
179
|
|
|
161
180
|
def invoke(
|
|
162
|
-
self,
|
|
163
|
-
|
|
181
|
+
self,
|
|
182
|
+
messages: List[Message],
|
|
183
|
+
assistant_message: Message,
|
|
184
|
+
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
185
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
186
|
+
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
187
|
+
run_response: Optional[RunOutput] = None,
|
|
188
|
+
compress_tool_results: bool = False,
|
|
189
|
+
) -> ModelResponse:
|
|
164
190
|
"""
|
|
165
191
|
Invoke a non-streamed chat response from the Cohere API.
|
|
192
|
+
"""
|
|
193
|
+
request_kwargs = self.get_request_params(response_format=response_format, tools=tools)
|
|
166
194
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
195
|
+
try:
|
|
196
|
+
if run_response and run_response.metrics:
|
|
197
|
+
run_response.metrics.set_time_to_first_token()
|
|
170
198
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
199
|
+
assistant_message.metrics.start_timer()
|
|
200
|
+
provider_response = self.get_client().chat(
|
|
201
|
+
model=self.id,
|
|
202
|
+
messages=format_messages(messages, compress_tool_results), # type: ignore
|
|
203
|
+
**request_kwargs,
|
|
204
|
+
) # type: ignore
|
|
205
|
+
assistant_message.metrics.stop_timer()
|
|
206
|
+
|
|
207
|
+
model_response = self._parse_provider_response(provider_response, response_format=response_format)
|
|
208
|
+
|
|
209
|
+
return model_response
|
|
175
210
|
|
|
176
|
-
|
|
211
|
+
except Exception as e:
|
|
212
|
+
log_error(f"Unexpected error calling Cohere API: {str(e)}")
|
|
213
|
+
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
177
214
|
|
|
178
215
|
def invoke_stream(
|
|
179
|
-
self,
|
|
180
|
-
|
|
216
|
+
self,
|
|
217
|
+
messages: List[Message],
|
|
218
|
+
assistant_message: Message,
|
|
219
|
+
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
220
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
221
|
+
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
222
|
+
run_response: Optional[RunOutput] = None,
|
|
223
|
+
compress_tool_results: bool = False,
|
|
224
|
+
) -> Iterator[ModelResponse]:
|
|
181
225
|
"""
|
|
182
226
|
Invoke a streamed chat response from the Cohere API.
|
|
227
|
+
"""
|
|
228
|
+
request_kwargs = self.get_request_params(response_format=response_format, tools=tools)
|
|
183
229
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
230
|
+
try:
|
|
231
|
+
if run_response and run_response.metrics:
|
|
232
|
+
run_response.metrics.set_time_to_first_token()
|
|
187
233
|
|
|
188
|
-
|
|
189
|
-
Iterator[StreamedChatResponse]: An iterator of streamed chat responses.
|
|
190
|
-
"""
|
|
191
|
-
chat_message, api_kwargs = self._prepare_for_invoke(messages, tool_results)
|
|
234
|
+
tool_use: Dict[str, Any] = {}
|
|
192
235
|
|
|
193
|
-
|
|
236
|
+
assistant_message.metrics.start_timer()
|
|
194
237
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
238
|
+
for response in self.get_client().chat_stream(
|
|
239
|
+
model=self.id,
|
|
240
|
+
messages=format_messages(messages, compress_tool_results), # type: ignore
|
|
241
|
+
**request_kwargs,
|
|
242
|
+
):
|
|
243
|
+
model_response, tool_use = self._parse_provider_response_delta(response, tool_use=tool_use)
|
|
244
|
+
yield model_response
|
|
198
245
|
|
|
199
|
-
|
|
200
|
-
and prepares them for execution. It also handles errors if functions
|
|
201
|
-
are not found or if there are issues with the function calls.
|
|
246
|
+
assistant_message.metrics.stop_timer()
|
|
202
247
|
|
|
203
|
-
|
|
204
|
-
|
|
248
|
+
except Exception as e:
|
|
249
|
+
log_error(f"Unexpected error calling Cohere API: {str(e)}")
|
|
250
|
+
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
205
251
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
252
|
+
async def ainvoke(
|
|
253
|
+
self,
|
|
254
|
+
messages: List[Message],
|
|
255
|
+
assistant_message: Message,
|
|
256
|
+
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
257
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
258
|
+
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
259
|
+
run_response: Optional[RunOutput] = None,
|
|
260
|
+
compress_tool_results: bool = False,
|
|
261
|
+
) -> ModelResponse:
|
|
209
262
|
"""
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
# Check if tool_calls is None or empty
|
|
214
|
-
if not agent_message.tool_calls:
|
|
215
|
-
return function_calls_to_run, error_messages
|
|
263
|
+
Asynchronously invoke a non-streamed chat response from the Cohere API.
|
|
264
|
+
"""
|
|
265
|
+
request_kwargs = self.get_request_params(response_format=response_format, tools=tools)
|
|
216
266
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
_function_call = get_function_call_for_tool_call(tool_call, self._functions)
|
|
267
|
+
try:
|
|
268
|
+
if run_response and run_response.metrics:
|
|
269
|
+
run_response.metrics.set_time_to_first_token()
|
|
221
270
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
271
|
+
assistant_message.metrics.start_timer()
|
|
272
|
+
provider_response = await self.get_async_client().chat(
|
|
273
|
+
model=self.id,
|
|
274
|
+
messages=format_messages(messages, compress_tool_results), # type: ignore
|
|
275
|
+
**request_kwargs,
|
|
276
|
+
)
|
|
277
|
+
assistant_message.metrics.stop_timer()
|
|
226
278
|
|
|
227
|
-
|
|
228
|
-
if _function_call.error is not None:
|
|
229
|
-
error_messages.append(Message(role="user", content=_function_call.error))
|
|
230
|
-
continue
|
|
279
|
+
model_response = self._parse_provider_response(provider_response, response_format=response_format)
|
|
231
280
|
|
|
232
|
-
|
|
233
|
-
function_calls_to_run.append(_function_call)
|
|
281
|
+
return model_response
|
|
234
282
|
|
|
235
|
-
|
|
283
|
+
except Exception as e:
|
|
284
|
+
log_error(f"Unexpected error calling Cohere API: {str(e)}")
|
|
285
|
+
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
236
286
|
|
|
237
|
-
def
|
|
287
|
+
async def ainvoke_stream(
|
|
238
288
|
self,
|
|
239
|
-
assistant_message: Message,
|
|
240
289
|
messages: List[Message],
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
290
|
+
assistant_message: Message,
|
|
291
|
+
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
292
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
293
|
+
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
294
|
+
run_response: Optional[RunOutput] = None,
|
|
295
|
+
compress_tool_results: bool = False,
|
|
296
|
+
) -> AsyncIterator[ModelResponse]:
|
|
244
297
|
"""
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
Args:
|
|
248
|
-
assistant_message (Message): The assistant message.
|
|
249
|
-
messages (List[Message]): The list of messages.
|
|
250
|
-
response_tool_calls (List[Any]): The list of response tool calls.
|
|
251
|
-
model_response (ModelResponse): The model response.
|
|
252
|
-
|
|
253
|
-
Returns:
|
|
254
|
-
Optional[Any]: The tool results.
|
|
298
|
+
Asynchronously invoke a streamed chat response from the Cohere API.
|
|
255
299
|
"""
|
|
300
|
+
request_kwargs = self.get_request_params(response_format=response_format, tools=tools)
|
|
256
301
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
function_call_results: List[Message] = []
|
|
261
|
-
if assistant_message.tool_calls is None:
|
|
262
|
-
return None
|
|
263
|
-
|
|
264
|
-
if model_response.tool_calls is None:
|
|
265
|
-
model_response.tool_calls = []
|
|
266
|
-
|
|
267
|
-
for tool_call in assistant_message.tool_calls:
|
|
268
|
-
_tool_call_id = tool_call.get("id")
|
|
269
|
-
_function_call = get_function_call_for_tool_call(tool_call, self._functions)
|
|
270
|
-
if _function_call is None:
|
|
271
|
-
messages.append(
|
|
272
|
-
Message(
|
|
273
|
-
role="tool",
|
|
274
|
-
tool_call_id=_tool_call_id,
|
|
275
|
-
content="Could not find function to call.",
|
|
276
|
-
)
|
|
277
|
-
)
|
|
278
|
-
continue
|
|
279
|
-
if _function_call.error is not None:
|
|
280
|
-
messages.append(
|
|
281
|
-
Message(
|
|
282
|
-
role="tool",
|
|
283
|
-
tool_call_id=_tool_call_id,
|
|
284
|
-
content=_function_call.error,
|
|
285
|
-
)
|
|
286
|
-
)
|
|
287
|
-
continue
|
|
288
|
-
function_calls_to_run.append(_function_call)
|
|
289
|
-
|
|
290
|
-
model_response.content = assistant_message.get_content_string() + "\n\n"
|
|
302
|
+
try:
|
|
303
|
+
if run_response and run_response.metrics:
|
|
304
|
+
run_response.metrics.set_time_to_first_token()
|
|
291
305
|
|
|
292
|
-
|
|
293
|
-
model_response.content += "\nRunning:"
|
|
294
|
-
for _f in function_calls_to_run:
|
|
295
|
-
model_response.content += f"\n - {_f.get_call_str()}"
|
|
296
|
-
model_response.content += "\n\n"
|
|
306
|
+
tool_use: Dict[str, Any] = {}
|
|
297
307
|
|
|
298
|
-
|
|
308
|
+
assistant_message.metrics.start_timer()
|
|
299
309
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
function_call_response.event == ModelResponseEvent.tool_call_completed.value
|
|
305
|
-
and function_call_response.tool_calls is not None
|
|
310
|
+
async for response in self.get_async_client().chat_stream(
|
|
311
|
+
model=self.id,
|
|
312
|
+
messages=format_messages(messages, compress_tool_results), # type: ignore
|
|
313
|
+
**request_kwargs,
|
|
306
314
|
):
|
|
307
|
-
model_response.
|
|
315
|
+
model_response, tool_use = self._parse_provider_response_delta(response, tool_use=tool_use)
|
|
316
|
+
yield model_response
|
|
308
317
|
|
|
309
|
-
|
|
310
|
-
messages.extend(function_call_results)
|
|
311
|
-
|
|
312
|
-
# Prepare tool results for the next API call
|
|
313
|
-
if response_tool_calls:
|
|
314
|
-
tool_results = [
|
|
315
|
-
ToolResult(
|
|
316
|
-
call=tool_call,
|
|
317
|
-
outputs=[tool_call.parameters, {"result": fn_result.content}],
|
|
318
|
-
)
|
|
319
|
-
for tool_call, fn_result in zip(response_tool_calls, function_call_results)
|
|
320
|
-
]
|
|
321
|
-
else:
|
|
322
|
-
tool_results = None
|
|
318
|
+
assistant_message.metrics.stop_timer()
|
|
323
319
|
|
|
324
|
-
|
|
320
|
+
except Exception as e:
|
|
321
|
+
log_error(f"Unexpected error calling Cohere API: {str(e)}")
|
|
322
|
+
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
325
323
|
|
|
326
|
-
def
|
|
324
|
+
def _parse_provider_response(self, response: V2ChatResponse, **kwargs) -> ModelResponse:
|
|
327
325
|
"""
|
|
328
|
-
|
|
326
|
+
Parse the model provider response.
|
|
329
327
|
|
|
330
328
|
Args:
|
|
331
|
-
response (
|
|
332
|
-
|
|
333
|
-
Returns:
|
|
334
|
-
Message: The assistant message.
|
|
335
|
-
"""
|
|
336
|
-
response_content = response.text
|
|
337
|
-
return Message(role="assistant", content=response_content)
|
|
338
|
-
|
|
339
|
-
def response(self, messages: List[Message], tool_results: Optional[List[ToolResult]] = None) -> ModelResponse:
|
|
340
|
-
"""
|
|
341
|
-
Send a chat completion request to the Cohere API.
|
|
342
|
-
|
|
343
|
-
Args:
|
|
344
|
-
messages (List[Message]): A list of message objects representing the conversation.
|
|
345
|
-
|
|
346
|
-
Returns:
|
|
347
|
-
ModelResponse: The model response from the API.
|
|
329
|
+
response (V2ChatResponse): The response from the Cohere API.
|
|
348
330
|
"""
|
|
349
|
-
logger.debug("---------- Cohere Response Start ----------")
|
|
350
|
-
self._log_messages(messages)
|
|
351
331
|
model_response = ModelResponse()
|
|
352
332
|
|
|
353
|
-
|
|
354
|
-
response_timer = Timer()
|
|
355
|
-
response_timer.start()
|
|
356
|
-
logger.debug(f"Tool Results: {tool_results}")
|
|
357
|
-
response: NonStreamedChatResponse = self.invoke(messages=messages, tool_results=tool_results)
|
|
358
|
-
response_timer.stop()
|
|
359
|
-
logger.debug(f"Time to generate response: {response_timer.elapsed:.4f}s")
|
|
360
|
-
|
|
361
|
-
assistant_message = self._create_assistant_message(response)
|
|
362
|
-
|
|
363
|
-
# Process tool calls if present
|
|
364
|
-
response_tool_calls = response.tool_calls
|
|
365
|
-
if response_tool_calls:
|
|
366
|
-
tool_calls = [
|
|
367
|
-
{
|
|
368
|
-
"type": "function",
|
|
369
|
-
"function": {
|
|
370
|
-
"name": tools.name,
|
|
371
|
-
"arguments": json.dumps(tools.parameters),
|
|
372
|
-
},
|
|
373
|
-
}
|
|
374
|
-
for tools in response_tool_calls
|
|
375
|
-
]
|
|
376
|
-
assistant_message.tool_calls = tool_calls
|
|
377
|
-
|
|
378
|
-
# Handle tool calls if present and tool running is enabled
|
|
379
|
-
if assistant_message.tool_calls:
|
|
380
|
-
tool_results = self._handle_tool_calls(
|
|
381
|
-
assistant_message=assistant_message,
|
|
382
|
-
messages=messages,
|
|
383
|
-
response_tool_calls=response_tool_calls,
|
|
384
|
-
model_response=model_response,
|
|
385
|
-
)
|
|
333
|
+
model_response.role = response.message.role
|
|
386
334
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
335
|
+
response_message = response.message
|
|
336
|
+
if response_message.content is not None:
|
|
337
|
+
full_content = ""
|
|
338
|
+
for item in response_message.content:
|
|
339
|
+
if hasattr(item, "text") and item.text is not None: # type: ignore
|
|
340
|
+
full_content += item.text # type: ignore
|
|
341
|
+
model_response.content = full_content
|
|
391
342
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
if model_response.content is None:
|
|
395
|
-
model_response.content = ""
|
|
396
|
-
model_response.content += response_after_tool_calls.content
|
|
397
|
-
return model_response
|
|
343
|
+
if response_message.tool_calls is not None:
|
|
344
|
+
model_response.tool_calls = [t.model_dump() for t in response_message.tool_calls]
|
|
398
345
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
model_response.content = assistant_message.get_content_string()
|
|
346
|
+
if response.usage is not None:
|
|
347
|
+
model_response.response_usage = self._get_metrics(response.usage)
|
|
402
348
|
|
|
403
|
-
logger.debug("---------- Cohere Response End ----------")
|
|
404
349
|
return model_response
|
|
405
350
|
|
|
406
|
-
def
|
|
351
|
+
def _parse_provider_response_delta(
|
|
352
|
+
self, response: V2ChatStreamResponse, tool_use: Dict[str, Any]
|
|
353
|
+
) -> Tuple[ModelResponse, Dict[str, Any]]: # type: ignore
|
|
407
354
|
"""
|
|
408
|
-
|
|
355
|
+
Parse the streaming response from the model provider into ModelResponse objects.
|
|
409
356
|
|
|
410
357
|
Args:
|
|
411
|
-
|
|
412
|
-
|
|
358
|
+
response: Raw response chunk from the model provider
|
|
359
|
+
|
|
360
|
+
Returns:
|
|
361
|
+
ModelResponse: Parsed response delta
|
|
413
362
|
"""
|
|
414
|
-
|
|
415
|
-
if stream_data.time_to_first_token is not None:
|
|
416
|
-
assistant_message.metrics["time_to_first_token"] = stream_data.time_to_first_token
|
|
417
|
-
|
|
418
|
-
if "response_times" not in self.metrics:
|
|
419
|
-
self.metrics["response_times"] = []
|
|
420
|
-
self.metrics["response_times"].append(stream_data.response_timer.elapsed)
|
|
421
|
-
if stream_data.time_to_first_token is not None:
|
|
422
|
-
if "time_to_first_token" not in self.metrics:
|
|
423
|
-
self.metrics["time_to_first_token"] = []
|
|
424
|
-
self.metrics["time_to_first_token"].append(stream_data.time_to_first_token)
|
|
425
|
-
if stream_data.completion_tokens > 0:
|
|
426
|
-
if "tokens_per_second" not in self.metrics:
|
|
427
|
-
self.metrics["tokens_per_second"] = []
|
|
428
|
-
self.metrics["tokens_per_second"].append(
|
|
429
|
-
f"{stream_data.completion_tokens / stream_data.response_timer.elapsed:.4f}"
|
|
430
|
-
)
|
|
363
|
+
model_response = ModelResponse()
|
|
431
364
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
365
|
+
# 1. Add content
|
|
366
|
+
if (
|
|
367
|
+
response.type == "content-delta"
|
|
368
|
+
and response.delta is not None
|
|
369
|
+
and response.delta.message is not None
|
|
370
|
+
and response.delta.message.content is not None
|
|
371
|
+
and response.delta.message.content.text is not None
|
|
372
|
+
):
|
|
373
|
+
model_response.content = response.delta.message.content.text
|
|
436
374
|
|
|
437
|
-
|
|
438
|
-
assistant_message.metrics["output_tokens"] = stream_data.response_completion_tokens
|
|
439
|
-
self.metrics["completion_tokens"] = (
|
|
440
|
-
self.metrics.get("completion_tokens", 0) + stream_data.response_completion_tokens
|
|
441
|
-
)
|
|
442
|
-
self.metrics["output_tokens"] = self.metrics.get("output_tokens", 0) + stream_data.response_completion_tokens
|
|
375
|
+
# 2. Add tool calls information
|
|
443
376
|
|
|
444
|
-
|
|
445
|
-
|
|
377
|
+
# 2.1 Add starting tool call
|
|
378
|
+
elif response.type == "tool-call-start" and response.delta is not None:
|
|
379
|
+
if response.delta.message is not None and response.delta.message.tool_calls is not None:
|
|
380
|
+
tool_use = response.delta.message.tool_calls.model_dump()
|
|
446
381
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
stream_data: StreamData = StreamData()
|
|
455
|
-
stream_data.response_timer.start()
|
|
456
|
-
|
|
457
|
-
stream_data.response_content = ""
|
|
458
|
-
tool_calls: List[Dict[str, Any]] = []
|
|
459
|
-
stream_data.response_tool_calls = []
|
|
460
|
-
last_delta: Optional[NonStreamedChatResponse] = None
|
|
461
|
-
|
|
462
|
-
for response in self.invoke_stream(messages=messages, tool_results=tool_results):
|
|
463
|
-
if isinstance(response, StreamStartStreamedChatResponse):
|
|
464
|
-
pass
|
|
465
|
-
|
|
466
|
-
if isinstance(response, TextGenerationStreamedChatResponse):
|
|
467
|
-
if response.text is not None:
|
|
468
|
-
stream_data.response_content += response.text
|
|
469
|
-
stream_data.completion_tokens += 1
|
|
470
|
-
if stream_data.completion_tokens == 1:
|
|
471
|
-
stream_data.time_to_first_token = stream_data.response_timer.elapsed
|
|
472
|
-
logger.debug(f"Time to first token: {stream_data.time_to_first_token:.4f}s")
|
|
473
|
-
yield ModelResponse(content=response.text)
|
|
474
|
-
|
|
475
|
-
if isinstance(response, ToolCallsChunkStreamedChatResponse):
|
|
476
|
-
if response.tool_call_delta is None:
|
|
477
|
-
yield ModelResponse(content=response.text)
|
|
478
|
-
|
|
479
|
-
# Detect if response is a tool call
|
|
480
|
-
if isinstance(response, ToolCallsGenerationStreamedChatResponse):
|
|
481
|
-
for tc in response.tool_calls:
|
|
482
|
-
stream_data.response_tool_calls.append(tc)
|
|
483
|
-
tool_calls.append(
|
|
484
|
-
{
|
|
485
|
-
"type": "function",
|
|
486
|
-
"function": {
|
|
487
|
-
"name": tc.name,
|
|
488
|
-
"arguments": json.dumps(tc.parameters),
|
|
489
|
-
},
|
|
490
|
-
}
|
|
491
|
-
)
|
|
492
|
-
|
|
493
|
-
if isinstance(response, StreamEndStreamedChatResponse):
|
|
494
|
-
last_delta = response.response
|
|
495
|
-
|
|
496
|
-
yield ModelResponse(content="\n\n")
|
|
497
|
-
|
|
498
|
-
stream_data.response_timer.stop()
|
|
499
|
-
logger.debug(f"Time to generate response: {stream_data.response_timer.elapsed:.4f}s")
|
|
500
|
-
|
|
501
|
-
# -*- Create assistant message
|
|
502
|
-
assistant_message = Message(role="assistant", content=stream_data.response_content)
|
|
503
|
-
# -*- Add tool calls to assistant message
|
|
504
|
-
if len(stream_data.response_tool_calls) > 0:
|
|
505
|
-
assistant_message.tool_calls = tool_calls
|
|
506
|
-
|
|
507
|
-
# -*- Update usage metrics
|
|
508
|
-
# Add response time to metrics
|
|
509
|
-
assistant_message.metrics["time"] = stream_data.response_timer.elapsed
|
|
510
|
-
if "response_times" not in self.metrics:
|
|
511
|
-
self.metrics["response_times"] = []
|
|
512
|
-
self.metrics["response_times"].append(stream_data.response_timer.elapsed)
|
|
513
|
-
|
|
514
|
-
# Add token usage to metrics
|
|
515
|
-
meta: Optional[ApiMeta] = last_delta.meta if last_delta else None
|
|
516
|
-
tokens: Optional[ApiMetaTokens] = meta.tokens if meta else None
|
|
517
|
-
|
|
518
|
-
if tokens:
|
|
519
|
-
input_tokens = tokens.input_tokens
|
|
520
|
-
output_tokens = tokens.output_tokens
|
|
521
|
-
|
|
522
|
-
if input_tokens is not None:
|
|
523
|
-
assistant_message.metrics["input_tokens"] = input_tokens
|
|
524
|
-
self.metrics["input_tokens"] = self.metrics.get("input_tokens", 0) + input_tokens
|
|
525
|
-
|
|
526
|
-
if output_tokens is not None:
|
|
527
|
-
assistant_message.metrics["output_tokens"] = output_tokens
|
|
528
|
-
self.metrics["output_tokens"] = self.metrics.get("output_tokens", 0) + output_tokens
|
|
529
|
-
|
|
530
|
-
if input_tokens is not None and output_tokens is not None:
|
|
531
|
-
assistant_message.metrics["total_tokens"] = input_tokens + output_tokens
|
|
532
|
-
self.metrics["total_tokens"] = self.metrics.get("total_tokens", 0) + input_tokens + output_tokens
|
|
533
|
-
|
|
534
|
-
# -*- Add assistant message to messages
|
|
535
|
-
self._update_stream_metrics(stream_data=stream_data, assistant_message=assistant_message)
|
|
536
|
-
messages.append(assistant_message)
|
|
537
|
-
assistant_message.log()
|
|
538
|
-
logger.debug(f"Assistant Message: {assistant_message}")
|
|
539
|
-
|
|
540
|
-
# -*- Parse and run function call
|
|
541
|
-
if assistant_message.tool_calls is not None and len(assistant_message.tool_calls) > 0:
|
|
542
|
-
tool_role: str = "tool"
|
|
543
|
-
function_calls_to_run: List[FunctionCall] = []
|
|
544
|
-
function_call_results: List[Message] = []
|
|
545
|
-
for tool_call in assistant_message.tool_calls:
|
|
546
|
-
_tool_call_id = tool_call.get("id")
|
|
547
|
-
_function_call = get_function_call_for_tool_call(tool_call, self._functions)
|
|
548
|
-
if _function_call is None:
|
|
549
|
-
messages.append(
|
|
550
|
-
Message(
|
|
551
|
-
role=tool_role,
|
|
552
|
-
tool_call_id=_tool_call_id,
|
|
553
|
-
content="Could not find function to call.",
|
|
554
|
-
)
|
|
555
|
-
)
|
|
556
|
-
continue
|
|
557
|
-
if _function_call.error is not None:
|
|
558
|
-
messages.append(
|
|
559
|
-
Message(
|
|
560
|
-
role=tool_role,
|
|
561
|
-
tool_call_id=_tool_call_id,
|
|
562
|
-
content=_function_call.error,
|
|
563
|
-
)
|
|
564
|
-
)
|
|
565
|
-
continue
|
|
566
|
-
function_calls_to_run.append(_function_call)
|
|
567
|
-
|
|
568
|
-
if self.show_tool_calls:
|
|
569
|
-
if len(function_calls_to_run) == 1:
|
|
570
|
-
yield ModelResponse(content=f"- Running: {function_calls_to_run[0].get_call_str()}\n\n")
|
|
571
|
-
elif len(function_calls_to_run) > 1:
|
|
572
|
-
yield ModelResponse(content="Running:")
|
|
573
|
-
for _f in function_calls_to_run:
|
|
574
|
-
yield ModelResponse(content=f"\n - {_f.get_call_str()}")
|
|
575
|
-
yield ModelResponse(content="\n\n")
|
|
576
|
-
|
|
577
|
-
for intermediate_model_response in self.run_function_calls(
|
|
578
|
-
function_calls=function_calls_to_run, function_call_results=function_call_results, tool_role=tool_role
|
|
382
|
+
# 2.2 Add tool call delta
|
|
383
|
+
elif response.type == "tool-call-delta" and response.delta is not None:
|
|
384
|
+
if (
|
|
385
|
+
response.delta.message is not None
|
|
386
|
+
and response.delta.message.tool_calls is not None
|
|
387
|
+
and response.delta.message.tool_calls.function is not None
|
|
388
|
+
and response.delta.message.tool_calls.function.arguments is not None
|
|
579
389
|
):
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
390
|
+
tool_use["function"]["arguments"] += response.delta.message.tool_calls.function.arguments
|
|
391
|
+
|
|
392
|
+
# 2.3 Add ending tool call
|
|
393
|
+
elif response.type == "tool-call-end":
|
|
394
|
+
model_response.tool_calls = [tool_use]
|
|
395
|
+
|
|
396
|
+
# 3. Add metrics
|
|
397
|
+
elif (
|
|
398
|
+
response.type == "message-end"
|
|
399
|
+
and response.delta is not None
|
|
400
|
+
and response.delta.usage is not None
|
|
401
|
+
and response.delta.usage.tokens is not None
|
|
402
|
+
):
|
|
403
|
+
model_response.response_usage = self._get_metrics(response.delta.usage) # type: ignore
|
|
584
404
|
|
|
585
|
-
|
|
586
|
-
if stream_data.response_tool_calls is not None:
|
|
587
|
-
# Constructs a list named tool_results, where each element is a dictionary that contains details of tool calls and their outputs.
|
|
588
|
-
# It pairs each tool call in response_tool_calls with its corresponding result in function_call_results.
|
|
589
|
-
tool_results = [
|
|
590
|
-
ToolResult(call=tool_call, outputs=[tool_call.parameters, {"result": fn_result.content}])
|
|
591
|
-
for tool_call, fn_result in zip(stream_data.response_tool_calls, function_call_results)
|
|
592
|
-
]
|
|
593
|
-
messages.append(Message(role="user", content=""))
|
|
405
|
+
return model_response, tool_use
|
|
594
406
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
407
|
+
def _get_metrics(self, response_usage) -> Metrics:
|
|
408
|
+
"""
|
|
409
|
+
Parse the given Cohere usage into an Agno Metrics object.
|
|
598
410
|
|
|
599
|
-
|
|
600
|
-
|
|
411
|
+
Args:
|
|
412
|
+
response_usage: Usage data from Cohere
|
|
601
413
|
|
|
602
|
-
|
|
603
|
-
|
|
414
|
+
Returns:
|
|
415
|
+
Metrics: Parsed metrics data
|
|
416
|
+
"""
|
|
417
|
+
metrics = Metrics()
|
|
604
418
|
|
|
605
|
-
|
|
606
|
-
|
|
419
|
+
metrics.input_tokens = response_usage.tokens.input_tokens or 0
|
|
420
|
+
metrics.output_tokens = response_usage.tokens.output_tokens or 0
|
|
421
|
+
metrics.total_tokens = metrics.input_tokens + metrics.output_tokens
|
|
607
422
|
|
|
608
|
-
|
|
609
|
-
raise NotImplementedError(f"Async not supported on {self.name}.")
|
|
423
|
+
return metrics
|