agno 2.2.13__py3-none-any.whl → 2.4.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agno/agent/__init__.py +6 -0
- agno/agent/agent.py +5252 -3145
- agno/agent/remote.py +525 -0
- agno/api/api.py +2 -0
- agno/client/__init__.py +3 -0
- agno/client/a2a/__init__.py +10 -0
- agno/client/a2a/client.py +554 -0
- agno/client/a2a/schemas.py +112 -0
- agno/client/a2a/utils.py +369 -0
- agno/client/os.py +2669 -0
- agno/compression/__init__.py +3 -0
- agno/compression/manager.py +247 -0
- agno/culture/manager.py +2 -2
- agno/db/base.py +927 -6
- agno/db/dynamo/dynamo.py +788 -2
- agno/db/dynamo/schemas.py +128 -0
- agno/db/dynamo/utils.py +26 -3
- agno/db/firestore/firestore.py +674 -50
- agno/db/firestore/schemas.py +41 -0
- agno/db/firestore/utils.py +25 -10
- agno/db/gcs_json/gcs_json_db.py +506 -3
- agno/db/gcs_json/utils.py +14 -2
- agno/db/in_memory/in_memory_db.py +203 -4
- agno/db/in_memory/utils.py +14 -2
- agno/db/json/json_db.py +498 -2
- agno/db/json/utils.py +14 -2
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/utils.py +19 -0
- agno/db/migrations/v1_to_v2.py +54 -16
- agno/db/migrations/versions/__init__.py +0 -0
- agno/db/migrations/versions/v2_3_0.py +977 -0
- agno/db/mongo/async_mongo.py +1013 -39
- agno/db/mongo/mongo.py +684 -4
- agno/db/mongo/schemas.py +48 -0
- agno/db/mongo/utils.py +17 -0
- agno/db/mysql/__init__.py +2 -1
- agno/db/mysql/async_mysql.py +2958 -0
- agno/db/mysql/mysql.py +722 -53
- agno/db/mysql/schemas.py +77 -11
- agno/db/mysql/utils.py +151 -8
- agno/db/postgres/async_postgres.py +1254 -137
- agno/db/postgres/postgres.py +2316 -93
- agno/db/postgres/schemas.py +153 -21
- agno/db/postgres/utils.py +22 -7
- agno/db/redis/redis.py +531 -3
- agno/db/redis/schemas.py +36 -0
- agno/db/redis/utils.py +31 -15
- agno/db/schemas/evals.py +1 -0
- agno/db/schemas/memory.py +20 -9
- agno/db/singlestore/schemas.py +70 -1
- agno/db/singlestore/singlestore.py +737 -74
- agno/db/singlestore/utils.py +13 -3
- agno/db/sqlite/async_sqlite.py +1069 -89
- agno/db/sqlite/schemas.py +133 -1
- agno/db/sqlite/sqlite.py +2203 -165
- agno/db/sqlite/utils.py +21 -11
- agno/db/surrealdb/models.py +25 -0
- agno/db/surrealdb/surrealdb.py +603 -1
- agno/db/utils.py +60 -0
- agno/eval/__init__.py +26 -3
- agno/eval/accuracy.py +25 -12
- agno/eval/agent_as_judge.py +871 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +10 -4
- agno/eval/reliability.py +22 -13
- agno/eval/utils.py +2 -1
- agno/exceptions.py +42 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/client.py +13 -2
- agno/knowledge/__init__.py +4 -0
- agno/knowledge/chunking/code.py +90 -0
- agno/knowledge/chunking/document.py +65 -4
- agno/knowledge/chunking/fixed.py +4 -1
- agno/knowledge/chunking/markdown.py +102 -11
- agno/knowledge/chunking/recursive.py +2 -2
- agno/knowledge/chunking/semantic.py +130 -48
- agno/knowledge/chunking/strategy.py +18 -0
- agno/knowledge/embedder/azure_openai.py +0 -1
- agno/knowledge/embedder/google.py +1 -1
- agno/knowledge/embedder/mistral.py +1 -1
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/embedder/openai.py +16 -12
- agno/knowledge/filesystem.py +412 -0
- agno/knowledge/knowledge.py +4261 -1199
- agno/knowledge/protocol.py +134 -0
- agno/knowledge/reader/arxiv_reader.py +3 -2
- agno/knowledge/reader/base.py +9 -7
- agno/knowledge/reader/csv_reader.py +91 -42
- agno/knowledge/reader/docx_reader.py +9 -10
- agno/knowledge/reader/excel_reader.py +225 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +38 -48
- agno/knowledge/reader/firecrawl_reader.py +3 -2
- agno/knowledge/reader/json_reader.py +16 -22
- agno/knowledge/reader/markdown_reader.py +15 -14
- agno/knowledge/reader/pdf_reader.py +33 -28
- agno/knowledge/reader/pptx_reader.py +9 -10
- agno/knowledge/reader/reader_factory.py +135 -1
- agno/knowledge/reader/s3_reader.py +8 -16
- agno/knowledge/reader/tavily_reader.py +3 -3
- agno/knowledge/reader/text_reader.py +15 -14
- agno/knowledge/reader/utils/__init__.py +17 -0
- agno/knowledge/reader/utils/spreadsheet.py +114 -0
- agno/knowledge/reader/web_search_reader.py +8 -65
- agno/knowledge/reader/website_reader.py +16 -13
- agno/knowledge/reader/wikipedia_reader.py +36 -3
- agno/knowledge/reader/youtube_reader.py +3 -2
- agno/knowledge/remote_content/__init__.py +33 -0
- agno/knowledge/remote_content/config.py +266 -0
- agno/knowledge/remote_content/remote_content.py +105 -17
- agno/knowledge/utils.py +76 -22
- agno/learn/__init__.py +71 -0
- agno/learn/config.py +463 -0
- agno/learn/curate.py +185 -0
- agno/learn/machine.py +725 -0
- agno/learn/schemas.py +1114 -0
- agno/learn/stores/__init__.py +38 -0
- agno/learn/stores/decision_log.py +1156 -0
- agno/learn/stores/entity_memory.py +3275 -0
- agno/learn/stores/learned_knowledge.py +1583 -0
- agno/learn/stores/protocol.py +117 -0
- agno/learn/stores/session_context.py +1217 -0
- agno/learn/stores/user_memory.py +1495 -0
- agno/learn/stores/user_profile.py +1220 -0
- agno/learn/utils.py +209 -0
- agno/media.py +22 -6
- agno/memory/__init__.py +14 -1
- agno/memory/manager.py +223 -8
- agno/memory/strategies/__init__.py +15 -0
- agno/memory/strategies/base.py +66 -0
- agno/memory/strategies/summarize.py +196 -0
- agno/memory/strategies/types.py +37 -0
- agno/models/aimlapi/aimlapi.py +17 -0
- agno/models/anthropic/claude.py +434 -59
- agno/models/aws/bedrock.py +121 -20
- agno/models/aws/claude.py +131 -274
- agno/models/azure/ai_foundry.py +10 -6
- agno/models/azure/openai_chat.py +33 -10
- agno/models/base.py +1162 -561
- agno/models/cerebras/cerebras.py +120 -24
- agno/models/cerebras/cerebras_openai.py +21 -2
- agno/models/cohere/chat.py +65 -6
- agno/models/cometapi/cometapi.py +18 -1
- agno/models/dashscope/dashscope.py +2 -3
- agno/models/deepinfra/deepinfra.py +18 -1
- agno/models/deepseek/deepseek.py +69 -3
- agno/models/fireworks/fireworks.py +18 -1
- agno/models/google/gemini.py +959 -89
- agno/models/google/utils.py +22 -0
- agno/models/groq/groq.py +48 -18
- agno/models/huggingface/huggingface.py +17 -6
- agno/models/ibm/watsonx.py +16 -6
- agno/models/internlm/internlm.py +18 -1
- agno/models/langdb/langdb.py +13 -1
- agno/models/litellm/chat.py +88 -9
- agno/models/litellm/litellm_openai.py +18 -1
- agno/models/message.py +24 -5
- agno/models/meta/llama.py +40 -13
- agno/models/meta/llama_openai.py +22 -21
- agno/models/metrics.py +12 -0
- agno/models/mistral/mistral.py +8 -4
- agno/models/n1n/__init__.py +3 -0
- agno/models/n1n/n1n.py +57 -0
- agno/models/nebius/nebius.py +6 -7
- agno/models/nvidia/nvidia.py +20 -3
- agno/models/ollama/__init__.py +2 -0
- agno/models/ollama/chat.py +17 -6
- agno/models/ollama/responses.py +100 -0
- agno/models/openai/__init__.py +2 -0
- agno/models/openai/chat.py +117 -26
- agno/models/openai/open_responses.py +46 -0
- agno/models/openai/responses.py +110 -32
- agno/models/openrouter/__init__.py +2 -0
- agno/models/openrouter/openrouter.py +67 -2
- agno/models/openrouter/responses.py +146 -0
- agno/models/perplexity/perplexity.py +19 -1
- agno/models/portkey/portkey.py +7 -6
- agno/models/requesty/requesty.py +19 -2
- agno/models/response.py +20 -2
- agno/models/sambanova/sambanova.py +20 -3
- agno/models/siliconflow/siliconflow.py +19 -2
- agno/models/together/together.py +20 -3
- agno/models/vercel/v0.py +20 -3
- agno/models/vertexai/claude.py +124 -4
- agno/models/vllm/vllm.py +19 -14
- agno/models/xai/xai.py +19 -2
- agno/os/app.py +467 -137
- agno/os/auth.py +253 -5
- agno/os/config.py +22 -0
- agno/os/interfaces/a2a/a2a.py +7 -6
- agno/os/interfaces/a2a/router.py +635 -26
- agno/os/interfaces/a2a/utils.py +32 -33
- agno/os/interfaces/agui/agui.py +5 -3
- agno/os/interfaces/agui/router.py +26 -16
- agno/os/interfaces/agui/utils.py +97 -57
- agno/os/interfaces/base.py +7 -7
- agno/os/interfaces/slack/router.py +16 -7
- agno/os/interfaces/slack/slack.py +7 -7
- agno/os/interfaces/whatsapp/router.py +35 -7
- agno/os/interfaces/whatsapp/security.py +3 -1
- agno/os/interfaces/whatsapp/whatsapp.py +11 -8
- agno/os/managers.py +326 -0
- agno/os/mcp.py +652 -79
- agno/os/middleware/__init__.py +4 -0
- agno/os/middleware/jwt.py +718 -115
- agno/os/middleware/trailing_slash.py +27 -0
- agno/os/router.py +105 -1558
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +655 -0
- agno/os/routers/agents/schema.py +288 -0
- agno/os/routers/components/__init__.py +3 -0
- agno/os/routers/components/components.py +475 -0
- agno/os/routers/database.py +155 -0
- agno/os/routers/evals/evals.py +111 -18
- agno/os/routers/evals/schemas.py +38 -5
- agno/os/routers/evals/utils.py +80 -11
- agno/os/routers/health.py +3 -3
- agno/os/routers/knowledge/knowledge.py +284 -35
- agno/os/routers/knowledge/schemas.py +14 -2
- agno/os/routers/memory/memory.py +274 -11
- agno/os/routers/memory/schemas.py +44 -3
- agno/os/routers/metrics/metrics.py +30 -15
- agno/os/routers/metrics/schemas.py +10 -6
- agno/os/routers/registry/__init__.py +3 -0
- agno/os/routers/registry/registry.py +337 -0
- agno/os/routers/session/session.py +143 -14
- agno/os/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +550 -0
- agno/os/routers/teams/schema.py +280 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +549 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +757 -0
- agno/os/routers/workflows/schema.py +139 -0
- agno/os/schema.py +157 -584
- agno/os/scopes.py +469 -0
- agno/os/settings.py +3 -0
- agno/os/utils.py +574 -185
- agno/reasoning/anthropic.py +85 -1
- agno/reasoning/azure_ai_foundry.py +93 -1
- agno/reasoning/deepseek.py +102 -2
- agno/reasoning/default.py +6 -7
- agno/reasoning/gemini.py +87 -3
- agno/reasoning/groq.py +109 -2
- agno/reasoning/helpers.py +6 -7
- agno/reasoning/manager.py +1238 -0
- agno/reasoning/ollama.py +93 -1
- agno/reasoning/openai.py +115 -1
- agno/reasoning/vertexai.py +85 -1
- agno/registry/__init__.py +3 -0
- agno/registry/registry.py +68 -0
- agno/remote/__init__.py +3 -0
- agno/remote/base.py +581 -0
- agno/run/__init__.py +2 -4
- agno/run/agent.py +134 -19
- agno/run/base.py +49 -1
- agno/run/cancel.py +65 -52
- agno/run/cancellation_management/__init__.py +9 -0
- agno/run/cancellation_management/base.py +78 -0
- agno/run/cancellation_management/in_memory_cancellation_manager.py +100 -0
- agno/run/cancellation_management/redis_cancellation_manager.py +236 -0
- agno/run/requirement.py +181 -0
- agno/run/team.py +111 -19
- agno/run/workflow.py +2 -1
- agno/session/agent.py +57 -92
- agno/session/summary.py +1 -1
- agno/session/team.py +62 -115
- agno/session/workflow.py +353 -57
- agno/skills/__init__.py +17 -0
- agno/skills/agent_skills.py +377 -0
- agno/skills/errors.py +32 -0
- agno/skills/loaders/__init__.py +4 -0
- agno/skills/loaders/base.py +27 -0
- agno/skills/loaders/local.py +216 -0
- agno/skills/skill.py +65 -0
- agno/skills/utils.py +107 -0
- agno/skills/validator.py +277 -0
- agno/table.py +10 -0
- agno/team/__init__.py +5 -1
- agno/team/remote.py +447 -0
- agno/team/team.py +3769 -2202
- agno/tools/brandfetch.py +27 -18
- agno/tools/browserbase.py +225 -16
- agno/tools/crawl4ai.py +3 -0
- agno/tools/duckduckgo.py +25 -71
- agno/tools/exa.py +0 -21
- agno/tools/file.py +14 -13
- agno/tools/file_generation.py +12 -6
- agno/tools/firecrawl.py +15 -7
- agno/tools/function.py +94 -113
- agno/tools/google_bigquery.py +11 -2
- agno/tools/google_drive.py +4 -3
- agno/tools/knowledge.py +9 -4
- agno/tools/mcp/mcp.py +301 -18
- agno/tools/mcp/multi_mcp.py +269 -14
- agno/tools/mem0.py +11 -10
- agno/tools/memory.py +47 -46
- agno/tools/mlx_transcribe.py +10 -7
- agno/tools/models/nebius.py +5 -5
- agno/tools/models_labs.py +20 -10
- agno/tools/nano_banana.py +151 -0
- agno/tools/parallel.py +0 -7
- agno/tools/postgres.py +76 -36
- agno/tools/python.py +14 -6
- agno/tools/reasoning.py +30 -23
- agno/tools/redshift.py +406 -0
- agno/tools/shopify.py +1519 -0
- agno/tools/spotify.py +919 -0
- agno/tools/tavily.py +4 -1
- agno/tools/toolkit.py +253 -18
- agno/tools/websearch.py +93 -0
- agno/tools/website.py +1 -1
- agno/tools/wikipedia.py +1 -1
- agno/tools/workflow.py +56 -48
- agno/tools/yfinance.py +12 -11
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +161 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +112 -0
- agno/utils/agent.py +251 -10
- agno/utils/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +264 -7
- agno/utils/hooks.py +111 -3
- agno/utils/http.py +161 -2
- agno/utils/mcp.py +49 -8
- agno/utils/media.py +22 -1
- agno/utils/models/ai_foundry.py +9 -2
- agno/utils/models/claude.py +20 -5
- agno/utils/models/cohere.py +9 -2
- agno/utils/models/llama.py +9 -2
- agno/utils/models/mistral.py +4 -2
- agno/utils/os.py +0 -0
- agno/utils/print_response/agent.py +99 -16
- agno/utils/print_response/team.py +223 -24
- agno/utils/print_response/workflow.py +0 -2
- agno/utils/prompts.py +8 -6
- agno/utils/remote.py +23 -0
- agno/utils/response.py +1 -13
- agno/utils/string.py +91 -2
- agno/utils/team.py +62 -12
- agno/utils/tokens.py +657 -0
- agno/vectordb/base.py +15 -2
- agno/vectordb/cassandra/cassandra.py +1 -1
- agno/vectordb/chroma/__init__.py +2 -1
- agno/vectordb/chroma/chromadb.py +468 -23
- agno/vectordb/clickhouse/clickhousedb.py +1 -1
- agno/vectordb/couchbase/couchbase.py +6 -2
- agno/vectordb/lancedb/lance_db.py +7 -38
- agno/vectordb/lightrag/lightrag.py +7 -6
- agno/vectordb/milvus/milvus.py +118 -84
- agno/vectordb/mongodb/__init__.py +2 -1
- agno/vectordb/mongodb/mongodb.py +14 -31
- agno/vectordb/pgvector/pgvector.py +120 -66
- agno/vectordb/pineconedb/pineconedb.py +2 -19
- agno/vectordb/qdrant/__init__.py +2 -1
- agno/vectordb/qdrant/qdrant.py +33 -56
- agno/vectordb/redis/__init__.py +2 -1
- agno/vectordb/redis/redisdb.py +19 -31
- agno/vectordb/singlestore/singlestore.py +17 -9
- agno/vectordb/surrealdb/surrealdb.py +2 -38
- agno/vectordb/weaviate/__init__.py +2 -1
- agno/vectordb/weaviate/weaviate.py +7 -3
- agno/workflow/__init__.py +5 -1
- agno/workflow/agent.py +2 -2
- agno/workflow/condition.py +12 -10
- agno/workflow/loop.py +28 -9
- agno/workflow/parallel.py +21 -13
- agno/workflow/remote.py +362 -0
- agno/workflow/router.py +12 -9
- agno/workflow/step.py +261 -36
- agno/workflow/steps.py +12 -8
- agno/workflow/types.py +40 -77
- agno/workflow/workflow.py +939 -213
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/METADATA +134 -181
- agno-2.4.3.dist-info/RECORD +677 -0
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/WHEEL +1 -1
- agno/tools/googlesearch.py +0 -98
- agno/tools/memori.py +0 -339
- agno-2.2.13.dist-info/RECORD +0 -575
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/licenses/LICENSE +0 -0
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/top_level.txt +0 -0
agno/reasoning/ollama.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import List, Optional
|
|
3
|
+
from typing import AsyncIterator, Iterator, List, Optional, Tuple
|
|
4
4
|
|
|
5
5
|
from agno.models.base import Model
|
|
6
6
|
from agno.models.message import Message
|
|
@@ -65,3 +65,95 @@ async def aget_ollama_reasoning(reasoning_agent: "Agent", messages: List[Message
|
|
|
65
65
|
return Message(
|
|
66
66
|
role="assistant", content=f"<thinking>\n{reasoning_content}\n</thinking>", reasoning_content=reasoning_content
|
|
67
67
|
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def get_ollama_reasoning_stream(
|
|
71
|
+
reasoning_agent: "Agent", # type: ignore # noqa: F821
|
|
72
|
+
messages: List[Message],
|
|
73
|
+
) -> Iterator[Tuple[Optional[str], Optional[Message]]]:
|
|
74
|
+
"""
|
|
75
|
+
Stream reasoning content from Ollama model.
|
|
76
|
+
|
|
77
|
+
For reasoning models on Ollama (qwq, deepseek-r1, etc.), we use the main content output as reasoning content.
|
|
78
|
+
|
|
79
|
+
Yields:
|
|
80
|
+
Tuple of (reasoning_content_delta, final_message)
|
|
81
|
+
- During streaming: (reasoning_content_delta, None)
|
|
82
|
+
- At the end: (None, final_message)
|
|
83
|
+
"""
|
|
84
|
+
from agno.run.agent import RunEvent
|
|
85
|
+
|
|
86
|
+
reasoning_content: str = ""
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
for event in reasoning_agent.run(input=messages, stream=True, stream_events=True):
|
|
90
|
+
if hasattr(event, "event"):
|
|
91
|
+
if event.event == RunEvent.run_content:
|
|
92
|
+
# Check for reasoning_content attribute first (native reasoning)
|
|
93
|
+
if hasattr(event, "reasoning_content") and event.reasoning_content:
|
|
94
|
+
reasoning_content += event.reasoning_content
|
|
95
|
+
yield (event.reasoning_content, None)
|
|
96
|
+
# Use the main content as reasoning content
|
|
97
|
+
elif hasattr(event, "content") and event.content:
|
|
98
|
+
reasoning_content += event.content
|
|
99
|
+
yield (event.content, None)
|
|
100
|
+
elif event.event == RunEvent.run_completed:
|
|
101
|
+
pass
|
|
102
|
+
except Exception as e:
|
|
103
|
+
logger.warning(f"Reasoning error: {e}")
|
|
104
|
+
return
|
|
105
|
+
|
|
106
|
+
# Yield final message
|
|
107
|
+
if reasoning_content:
|
|
108
|
+
final_message = Message(
|
|
109
|
+
role="assistant",
|
|
110
|
+
content=f"<thinking>\n{reasoning_content}\n</thinking>",
|
|
111
|
+
reasoning_content=reasoning_content,
|
|
112
|
+
)
|
|
113
|
+
yield (None, final_message)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
async def aget_ollama_reasoning_stream(
|
|
117
|
+
reasoning_agent: "Agent", # type: ignore # noqa: F821
|
|
118
|
+
messages: List[Message],
|
|
119
|
+
) -> AsyncIterator[Tuple[Optional[str], Optional[Message]]]:
|
|
120
|
+
"""
|
|
121
|
+
Stream reasoning content from Ollama model asynchronously.
|
|
122
|
+
|
|
123
|
+
For reasoning models on Ollama (qwq, deepseek-r1, etc.), we use the main content output as reasoning content.
|
|
124
|
+
|
|
125
|
+
Yields:
|
|
126
|
+
Tuple of (reasoning_content_delta, final_message)
|
|
127
|
+
- During streaming: (reasoning_content_delta, None)
|
|
128
|
+
- At the end: (None, final_message)
|
|
129
|
+
"""
|
|
130
|
+
from agno.run.agent import RunEvent
|
|
131
|
+
|
|
132
|
+
reasoning_content: str = ""
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
async for event in reasoning_agent.arun(input=messages, stream=True, stream_events=True):
|
|
136
|
+
if hasattr(event, "event"):
|
|
137
|
+
if event.event == RunEvent.run_content:
|
|
138
|
+
# Check for reasoning_content attribute first (native reasoning)
|
|
139
|
+
if hasattr(event, "reasoning_content") and event.reasoning_content:
|
|
140
|
+
reasoning_content += event.reasoning_content
|
|
141
|
+
yield (event.reasoning_content, None)
|
|
142
|
+
# Use the main content as reasoning content
|
|
143
|
+
elif hasattr(event, "content") and event.content:
|
|
144
|
+
reasoning_content += event.content
|
|
145
|
+
yield (event.content, None)
|
|
146
|
+
elif event.event == RunEvent.run_completed:
|
|
147
|
+
pass
|
|
148
|
+
except Exception as e:
|
|
149
|
+
logger.warning(f"Reasoning error: {e}")
|
|
150
|
+
return
|
|
151
|
+
|
|
152
|
+
# Yield final message
|
|
153
|
+
if reasoning_content:
|
|
154
|
+
final_message = Message(
|
|
155
|
+
role="assistant",
|
|
156
|
+
content=f"<thinking>\n{reasoning_content}\n</thinking>",
|
|
157
|
+
reasoning_content=reasoning_content,
|
|
158
|
+
)
|
|
159
|
+
yield (None, final_message)
|
agno/reasoning/openai.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import List, Optional
|
|
3
|
+
from typing import AsyncIterator, Iterator, List, Optional, Tuple
|
|
4
4
|
|
|
5
5
|
from agno.models.base import Model
|
|
6
6
|
from agno.models.message import Message
|
|
@@ -21,6 +21,8 @@ def is_openai_reasoning_model(reasoning_model: Model) -> bool:
|
|
|
21
21
|
or ("o1" in reasoning_model.id)
|
|
22
22
|
or ("4.1" in reasoning_model.id)
|
|
23
23
|
or ("4.5" in reasoning_model.id)
|
|
24
|
+
or ("5.1" in reasoning_model.id)
|
|
25
|
+
or ("5.2" in reasoning_model.id)
|
|
24
26
|
)
|
|
25
27
|
) or (isinstance(reasoning_model, OpenAILike) and "deepseek-r1" in reasoning_model.id.lower())
|
|
26
28
|
|
|
@@ -84,3 +86,115 @@ async def aget_openai_reasoning(reasoning_agent: "Agent", messages: List[Message
|
|
|
84
86
|
return Message(
|
|
85
87
|
role="assistant", content=f"<thinking>\n{reasoning_content}\n</thinking>", reasoning_content=reasoning_content
|
|
86
88
|
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def get_openai_reasoning_stream(
|
|
92
|
+
reasoning_agent: "Agent", # type: ignore # noqa: F821
|
|
93
|
+
messages: List[Message],
|
|
94
|
+
) -> Iterator[Tuple[Optional[str], Optional[Message]]]:
|
|
95
|
+
"""
|
|
96
|
+
Stream reasoning content from OpenAI model.
|
|
97
|
+
|
|
98
|
+
For OpenAI reasoning models, we use the main content output as reasoning content.
|
|
99
|
+
|
|
100
|
+
Yields:
|
|
101
|
+
Tuple of (reasoning_content_delta, final_message)
|
|
102
|
+
- During streaming: (reasoning_content_delta, None)
|
|
103
|
+
- At the end: (None, final_message)
|
|
104
|
+
"""
|
|
105
|
+
from agno.run.agent import RunEvent
|
|
106
|
+
|
|
107
|
+
# Update system message role to "system"
|
|
108
|
+
for message in messages:
|
|
109
|
+
if message.role == "developer":
|
|
110
|
+
message.role = "system"
|
|
111
|
+
|
|
112
|
+
reasoning_content: str = ""
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
for event in reasoning_agent.run(input=messages, stream=True, stream_events=True):
|
|
116
|
+
if hasattr(event, "event"):
|
|
117
|
+
if event.event == RunEvent.run_content:
|
|
118
|
+
# Check for reasoning_content attribute first (native reasoning)
|
|
119
|
+
if hasattr(event, "reasoning_content") and event.reasoning_content:
|
|
120
|
+
reasoning_content += event.reasoning_content
|
|
121
|
+
yield (event.reasoning_content, None)
|
|
122
|
+
# Use the main content as reasoning content
|
|
123
|
+
elif hasattr(event, "content") and event.content:
|
|
124
|
+
reasoning_content += event.content
|
|
125
|
+
yield (event.content, None)
|
|
126
|
+
elif event.event == RunEvent.run_completed:
|
|
127
|
+
# Check for reasoning_content at completion (OpenAIResponses with reasoning_summary)
|
|
128
|
+
if hasattr(event, "reasoning_content") and event.reasoning_content:
|
|
129
|
+
# If we haven't accumulated any reasoning content yet, use this
|
|
130
|
+
if not reasoning_content:
|
|
131
|
+
reasoning_content = event.reasoning_content
|
|
132
|
+
yield (event.reasoning_content, None)
|
|
133
|
+
except Exception as e:
|
|
134
|
+
logger.warning(f"Reasoning error: {e}")
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
# Yield final message
|
|
138
|
+
if reasoning_content:
|
|
139
|
+
final_message = Message(
|
|
140
|
+
role="assistant",
|
|
141
|
+
content=f"<thinking>\n{reasoning_content}\n</thinking>",
|
|
142
|
+
reasoning_content=reasoning_content,
|
|
143
|
+
)
|
|
144
|
+
yield (None, final_message)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
async def aget_openai_reasoning_stream(
|
|
148
|
+
reasoning_agent: "Agent", # type: ignore # noqa: F821
|
|
149
|
+
messages: List[Message],
|
|
150
|
+
) -> AsyncIterator[Tuple[Optional[str], Optional[Message]]]:
|
|
151
|
+
"""
|
|
152
|
+
Stream reasoning content from OpenAI model asynchronously.
|
|
153
|
+
|
|
154
|
+
For OpenAI reasoning models, we use the main content output as reasoning content.
|
|
155
|
+
|
|
156
|
+
Yields:
|
|
157
|
+
Tuple of (reasoning_content_delta, final_message)
|
|
158
|
+
- During streaming: (reasoning_content_delta, None)
|
|
159
|
+
- At the end: (None, final_message)
|
|
160
|
+
"""
|
|
161
|
+
from agno.run.agent import RunEvent
|
|
162
|
+
|
|
163
|
+
# Update system message role to "system"
|
|
164
|
+
for message in messages:
|
|
165
|
+
if message.role == "developer":
|
|
166
|
+
message.role = "system"
|
|
167
|
+
|
|
168
|
+
reasoning_content: str = ""
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
async for event in reasoning_agent.arun(input=messages, stream=True, stream_events=True):
|
|
172
|
+
if hasattr(event, "event"):
|
|
173
|
+
if event.event == RunEvent.run_content:
|
|
174
|
+
# Check for reasoning_content attribute first (native reasoning)
|
|
175
|
+
if hasattr(event, "reasoning_content") and event.reasoning_content:
|
|
176
|
+
reasoning_content += event.reasoning_content
|
|
177
|
+
yield (event.reasoning_content, None)
|
|
178
|
+
# Use the main content as reasoning content
|
|
179
|
+
elif hasattr(event, "content") and event.content:
|
|
180
|
+
reasoning_content += event.content
|
|
181
|
+
yield (event.content, None)
|
|
182
|
+
elif event.event == RunEvent.run_completed:
|
|
183
|
+
# Check for reasoning_content at completion (OpenAIResponses with reasoning_summary)
|
|
184
|
+
if hasattr(event, "reasoning_content") and event.reasoning_content:
|
|
185
|
+
# If we haven't accumulated any reasoning content yet, use this
|
|
186
|
+
if not reasoning_content:
|
|
187
|
+
reasoning_content = event.reasoning_content
|
|
188
|
+
yield (event.reasoning_content, None)
|
|
189
|
+
except Exception as e:
|
|
190
|
+
logger.warning(f"Reasoning error: {e}")
|
|
191
|
+
return
|
|
192
|
+
|
|
193
|
+
# Yield final message
|
|
194
|
+
if reasoning_content:
|
|
195
|
+
final_message = Message(
|
|
196
|
+
role="assistant",
|
|
197
|
+
content=f"<thinking>\n{reasoning_content}\n</thinking>",
|
|
198
|
+
reasoning_content=reasoning_content,
|
|
199
|
+
)
|
|
200
|
+
yield (None, final_message)
|
agno/reasoning/vertexai.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import List, Optional
|
|
3
|
+
from typing import AsyncIterator, Iterator, List, Optional, Tuple
|
|
4
4
|
|
|
5
5
|
from agno.models.base import Model
|
|
6
6
|
from agno.models.message import Message
|
|
@@ -74,3 +74,87 @@ async def aget_vertexai_reasoning(reasoning_agent: "Agent", messages: List[Messa
|
|
|
74
74
|
reasoning_content=reasoning_content,
|
|
75
75
|
redacted_reasoning_content=redacted_reasoning_content,
|
|
76
76
|
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def get_vertexai_reasoning_stream(
|
|
80
|
+
reasoning_agent: "Agent", # type: ignore # noqa: F821
|
|
81
|
+
messages: List[Message],
|
|
82
|
+
) -> Iterator[Tuple[Optional[str], Optional[Message]]]:
|
|
83
|
+
"""
|
|
84
|
+
Stream reasoning content from VertexAI Claude model.
|
|
85
|
+
|
|
86
|
+
Yields:
|
|
87
|
+
Tuple of (reasoning_content_delta, final_message)
|
|
88
|
+
- During streaming: (reasoning_content_delta, None)
|
|
89
|
+
- At the end: (None, final_message)
|
|
90
|
+
"""
|
|
91
|
+
from agno.run.agent import RunEvent
|
|
92
|
+
|
|
93
|
+
reasoning_content: str = ""
|
|
94
|
+
redacted_reasoning_content: Optional[str] = None
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
for event in reasoning_agent.run(input=messages, stream=True, stream_events=True):
|
|
98
|
+
if hasattr(event, "event"):
|
|
99
|
+
if event.event == RunEvent.run_content:
|
|
100
|
+
# Stream reasoning content as it arrives
|
|
101
|
+
if hasattr(event, "reasoning_content") and event.reasoning_content:
|
|
102
|
+
reasoning_content += event.reasoning_content
|
|
103
|
+
yield (event.reasoning_content, None)
|
|
104
|
+
elif event.event == RunEvent.run_completed:
|
|
105
|
+
pass
|
|
106
|
+
except Exception as e:
|
|
107
|
+
logger.warning(f"Reasoning error: {e}")
|
|
108
|
+
return
|
|
109
|
+
|
|
110
|
+
# Yield final message
|
|
111
|
+
if reasoning_content:
|
|
112
|
+
final_message = Message(
|
|
113
|
+
role="assistant",
|
|
114
|
+
content=f"<thinking>\n{reasoning_content}\n</thinking>",
|
|
115
|
+
reasoning_content=reasoning_content,
|
|
116
|
+
redacted_reasoning_content=redacted_reasoning_content,
|
|
117
|
+
)
|
|
118
|
+
yield (None, final_message)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
async def aget_vertexai_reasoning_stream(
|
|
122
|
+
reasoning_agent: "Agent", # type: ignore # noqa: F821
|
|
123
|
+
messages: List[Message],
|
|
124
|
+
) -> AsyncIterator[Tuple[Optional[str], Optional[Message]]]:
|
|
125
|
+
"""
|
|
126
|
+
Stream reasoning content from VertexAI Claude model asynchronously.
|
|
127
|
+
|
|
128
|
+
Yields:
|
|
129
|
+
Tuple of (reasoning_content_delta, final_message)
|
|
130
|
+
- During streaming: (reasoning_content_delta, None)
|
|
131
|
+
- At the end: (None, final_message)
|
|
132
|
+
"""
|
|
133
|
+
from agno.run.agent import RunEvent
|
|
134
|
+
|
|
135
|
+
reasoning_content: str = ""
|
|
136
|
+
redacted_reasoning_content: Optional[str] = None
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
async for event in reasoning_agent.arun(input=messages, stream=True, stream_events=True):
|
|
140
|
+
if hasattr(event, "event"):
|
|
141
|
+
if event.event == RunEvent.run_content:
|
|
142
|
+
# Stream reasoning content as it arrives
|
|
143
|
+
if hasattr(event, "reasoning_content") and event.reasoning_content:
|
|
144
|
+
reasoning_content += event.reasoning_content
|
|
145
|
+
yield (event.reasoning_content, None)
|
|
146
|
+
elif event.event == RunEvent.run_completed:
|
|
147
|
+
pass
|
|
148
|
+
except Exception as e:
|
|
149
|
+
logger.warning(f"Reasoning error: {e}")
|
|
150
|
+
return
|
|
151
|
+
|
|
152
|
+
# Yield final message
|
|
153
|
+
if reasoning_content:
|
|
154
|
+
final_message = Message(
|
|
155
|
+
role="assistant",
|
|
156
|
+
content=f"<thinking>\n{reasoning_content}\n</thinking>",
|
|
157
|
+
reasoning_content=reasoning_content,
|
|
158
|
+
redacted_reasoning_content=redacted_reasoning_content,
|
|
159
|
+
)
|
|
160
|
+
yield (None, final_message)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from functools import cached_property
|
|
3
|
+
from typing import Any, Callable, Dict, List, Optional, Type
|
|
4
|
+
from uuid import uuid4
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel
|
|
7
|
+
|
|
8
|
+
from agno.db.base import BaseDb
|
|
9
|
+
from agno.models.base import Model
|
|
10
|
+
from agno.tools.function import Function
|
|
11
|
+
from agno.tools.toolkit import Toolkit
|
|
12
|
+
from agno.vectordb.base import VectorDb
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class Registry:
|
|
17
|
+
"""
|
|
18
|
+
Registry is used to manage non serializable objects like tools, models, databases and vector databases.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
name: Optional[str] = None
|
|
22
|
+
description: Optional[str] = None
|
|
23
|
+
id: str = field(default_factory=lambda: str(uuid4()))
|
|
24
|
+
tools: List[Any] = field(default_factory=list)
|
|
25
|
+
models: List[Model] = field(default_factory=list)
|
|
26
|
+
dbs: List[BaseDb] = field(default_factory=list)
|
|
27
|
+
vector_dbs: List[VectorDb] = field(default_factory=list)
|
|
28
|
+
schemas: List[Type[BaseModel]] = field(default_factory=list)
|
|
29
|
+
|
|
30
|
+
@cached_property
|
|
31
|
+
def _entrypoint_lookup(self) -> Dict[str, Callable]:
|
|
32
|
+
lookup: Dict[str, Callable] = {}
|
|
33
|
+
for tool in self.tools:
|
|
34
|
+
if isinstance(tool, Toolkit):
|
|
35
|
+
for func in tool.functions.values():
|
|
36
|
+
if func.entrypoint is not None:
|
|
37
|
+
lookup[func.name] = func.entrypoint
|
|
38
|
+
elif isinstance(tool, Function):
|
|
39
|
+
if tool.entrypoint is not None:
|
|
40
|
+
lookup[tool.name] = tool.entrypoint
|
|
41
|
+
elif callable(tool):
|
|
42
|
+
lookup[tool.__name__] = tool
|
|
43
|
+
return lookup
|
|
44
|
+
|
|
45
|
+
def rehydrate_function(self, func_dict: Dict[str, Any]) -> Function:
|
|
46
|
+
"""Reconstruct a Function from dict, reattaching its entrypoint."""
|
|
47
|
+
func = Function.from_dict(func_dict)
|
|
48
|
+
func.entrypoint = self._entrypoint_lookup.get(func.name)
|
|
49
|
+
return func
|
|
50
|
+
|
|
51
|
+
def get_schema(self, name: str) -> Optional[Type[BaseModel]]:
|
|
52
|
+
"""Get a schema by name."""
|
|
53
|
+
if self.schemas:
|
|
54
|
+
return next((s for s in self.schemas if s.__name__ == name), None)
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
def get_db(self, db_id: str) -> Optional[BaseDb]:
|
|
58
|
+
"""Get a database by id from the registry.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
db_id: The database id to look up
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
The database instance if found, None otherwise
|
|
65
|
+
"""
|
|
66
|
+
if self.dbs:
|
|
67
|
+
return next((db for db in self.dbs if db.id == db_id), None)
|
|
68
|
+
return None
|
agno/remote/__init__.py
ADDED