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/anthropic.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
|
|
@@ -51,6 +51,48 @@ def get_anthropic_reasoning(reasoning_agent: "Agent", messages: List[Message]) -
|
|
|
51
51
|
)
|
|
52
52
|
|
|
53
53
|
|
|
54
|
+
def get_anthropic_reasoning_stream(
|
|
55
|
+
reasoning_agent: "Agent", # type: ignore # noqa: F821
|
|
56
|
+
messages: List[Message],
|
|
57
|
+
) -> Iterator[Tuple[Optional[str], Optional[Message]]]:
|
|
58
|
+
"""
|
|
59
|
+
Stream reasoning content from Anthropic Claude model.
|
|
60
|
+
|
|
61
|
+
Yields:
|
|
62
|
+
Tuple of (reasoning_content_delta, final_message)
|
|
63
|
+
- During streaming: (reasoning_content_delta, None)
|
|
64
|
+
- At the end: (None, final_message)
|
|
65
|
+
"""
|
|
66
|
+
from agno.run.agent import RunEvent
|
|
67
|
+
|
|
68
|
+
reasoning_content: str = ""
|
|
69
|
+
redacted_reasoning_content: Optional[str] = None
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
for event in reasoning_agent.run(input=messages, stream=True, stream_events=True):
|
|
73
|
+
if hasattr(event, "event"):
|
|
74
|
+
if event.event == RunEvent.run_content:
|
|
75
|
+
# Stream reasoning content as it arrives
|
|
76
|
+
if hasattr(event, "reasoning_content") and event.reasoning_content:
|
|
77
|
+
reasoning_content += event.reasoning_content
|
|
78
|
+
yield (event.reasoning_content, None)
|
|
79
|
+
elif event.event == RunEvent.run_completed:
|
|
80
|
+
pass
|
|
81
|
+
except Exception as e:
|
|
82
|
+
logger.warning(f"Reasoning error: {e}")
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
# Yield final message
|
|
86
|
+
if reasoning_content:
|
|
87
|
+
final_message = Message(
|
|
88
|
+
role="assistant",
|
|
89
|
+
content=f"<thinking>\n{reasoning_content}\n</thinking>",
|
|
90
|
+
reasoning_content=reasoning_content,
|
|
91
|
+
redacted_reasoning_content=redacted_reasoning_content,
|
|
92
|
+
)
|
|
93
|
+
yield (None, final_message)
|
|
94
|
+
|
|
95
|
+
|
|
54
96
|
async def aget_anthropic_reasoning(reasoning_agent: "Agent", messages: List[Message]) -> Optional[Message]: # type: ignore # noqa: F821
|
|
55
97
|
"""Get reasoning from an Anthropic Claude model asynchronously."""
|
|
56
98
|
from agno.run.agent import RunOutput
|
|
@@ -78,3 +120,45 @@ async def aget_anthropic_reasoning(reasoning_agent: "Agent", messages: List[Mess
|
|
|
78
120
|
reasoning_content=reasoning_content,
|
|
79
121
|
redacted_reasoning_content=redacted_reasoning_content,
|
|
80
122
|
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
async def aget_anthropic_reasoning_stream(
|
|
126
|
+
reasoning_agent: "Agent", # type: ignore # noqa: F821
|
|
127
|
+
messages: List[Message],
|
|
128
|
+
) -> AsyncIterator[Tuple[Optional[str], Optional[Message]]]:
|
|
129
|
+
"""
|
|
130
|
+
Stream reasoning content from Anthropic Claude model asynchronously.
|
|
131
|
+
|
|
132
|
+
Yields:
|
|
133
|
+
Tuple of (reasoning_content_delta, final_message)
|
|
134
|
+
- During streaming: (reasoning_content_delta, None)
|
|
135
|
+
- At the end: (None, final_message)
|
|
136
|
+
"""
|
|
137
|
+
from agno.run.agent import RunEvent
|
|
138
|
+
|
|
139
|
+
reasoning_content: str = ""
|
|
140
|
+
redacted_reasoning_content: Optional[str] = None
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
async for event in reasoning_agent.arun(input=messages, stream=True, stream_events=True):
|
|
144
|
+
if hasattr(event, "event"):
|
|
145
|
+
if event.event == RunEvent.run_content:
|
|
146
|
+
# Stream reasoning content as it arrives
|
|
147
|
+
if hasattr(event, "reasoning_content") and event.reasoning_content:
|
|
148
|
+
reasoning_content += event.reasoning_content
|
|
149
|
+
yield (event.reasoning_content, None)
|
|
150
|
+
elif event.event == RunEvent.run_completed:
|
|
151
|
+
pass
|
|
152
|
+
except Exception as e:
|
|
153
|
+
logger.warning(f"Reasoning error: {e}")
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
# Yield final message
|
|
157
|
+
if reasoning_content:
|
|
158
|
+
final_message = Message(
|
|
159
|
+
role="assistant",
|
|
160
|
+
content=f"<thinking>\n{reasoning_content}\n</thinking>",
|
|
161
|
+
reasoning_content=reasoning_content,
|
|
162
|
+
redacted_reasoning_content=redacted_reasoning_content,
|
|
163
|
+
)
|
|
164
|
+
yield (None, final_message)
|
|
@@ -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_ai_foundry_reasoning(reasoning_agent: "Agent", messages: List[Mes
|
|
|
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_ai_foundry_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 Azure AI Foundry model.
|
|
76
|
+
|
|
77
|
+
For DeepSeek-R1 models, 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_ai_foundry_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 Azure AI Foundry model asynchronously.
|
|
122
|
+
|
|
123
|
+
For DeepSeek-R1 models, 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/deepseek.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
|
|
@@ -8,7 +8,17 @@ from agno.utils.log import logger
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def is_deepseek_reasoning_model(reasoning_model: Model) -> bool:
|
|
11
|
-
|
|
11
|
+
"""Check if the model is a DeepSeek reasoning model.
|
|
12
|
+
|
|
13
|
+
Matches:
|
|
14
|
+
- deepseek-reasoner
|
|
15
|
+
- deepseek-r1 and variants (deepseek-r1-distill-*, etc.)
|
|
16
|
+
"""
|
|
17
|
+
if reasoning_model.__class__.__name__ != "DeepSeek":
|
|
18
|
+
return False
|
|
19
|
+
|
|
20
|
+
model_id = reasoning_model.id.lower()
|
|
21
|
+
return "reasoner" in model_id or "r1" in model_id
|
|
12
22
|
|
|
13
23
|
|
|
14
24
|
def get_deepseek_reasoning(reasoning_agent: "Agent", messages: List[Message]) -> Optional[Message]: # type: ignore # noqa: F821
|
|
@@ -37,6 +47,51 @@ def get_deepseek_reasoning(reasoning_agent: "Agent", messages: List[Message]) ->
|
|
|
37
47
|
)
|
|
38
48
|
|
|
39
49
|
|
|
50
|
+
def get_deepseek_reasoning_stream(
|
|
51
|
+
reasoning_agent: "Agent", # type: ignore # noqa: F821
|
|
52
|
+
messages: List[Message],
|
|
53
|
+
) -> Iterator[Tuple[Optional[str], Optional[Message]]]:
|
|
54
|
+
"""
|
|
55
|
+
Stream reasoning content from DeepSeek model.
|
|
56
|
+
|
|
57
|
+
Yields:
|
|
58
|
+
Tuple of (reasoning_content_delta, final_message)
|
|
59
|
+
- During streaming: (reasoning_content_delta, None)
|
|
60
|
+
- At the end: (None, final_message)
|
|
61
|
+
"""
|
|
62
|
+
from agno.run.agent import RunEvent
|
|
63
|
+
|
|
64
|
+
# Update system message role to "system"
|
|
65
|
+
for message in messages:
|
|
66
|
+
if message.role == "developer":
|
|
67
|
+
message.role = "system"
|
|
68
|
+
|
|
69
|
+
reasoning_content: str = ""
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
for event in reasoning_agent.run(input=messages, stream=True, stream_events=True):
|
|
73
|
+
if hasattr(event, "event"):
|
|
74
|
+
if event.event == RunEvent.run_content:
|
|
75
|
+
# Stream reasoning content as it arrives
|
|
76
|
+
if hasattr(event, "reasoning_content") and event.reasoning_content:
|
|
77
|
+
reasoning_content += event.reasoning_content
|
|
78
|
+
yield (event.reasoning_content, None)
|
|
79
|
+
elif event.event == RunEvent.run_completed:
|
|
80
|
+
pass
|
|
81
|
+
except Exception as e:
|
|
82
|
+
logger.warning(f"Reasoning error: {e}")
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
# Yield final message
|
|
86
|
+
if reasoning_content:
|
|
87
|
+
final_message = Message(
|
|
88
|
+
role="assistant",
|
|
89
|
+
content=f"<thinking>\n{reasoning_content}\n</thinking>",
|
|
90
|
+
reasoning_content=reasoning_content,
|
|
91
|
+
)
|
|
92
|
+
yield (None, final_message)
|
|
93
|
+
|
|
94
|
+
|
|
40
95
|
async def aget_deepseek_reasoning(reasoning_agent: "Agent", messages: List[Message]) -> Optional[Message]: # type: ignore # noqa: F821
|
|
41
96
|
from agno.run.agent import RunOutput
|
|
42
97
|
|
|
@@ -61,3 +116,48 @@ async def aget_deepseek_reasoning(reasoning_agent: "Agent", messages: List[Messa
|
|
|
61
116
|
return Message(
|
|
62
117
|
role="assistant", content=f"<thinking>\n{reasoning_content}\n</thinking>", reasoning_content=reasoning_content
|
|
63
118
|
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
async def aget_deepseek_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 DeepSeek 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
|
+
# Update system message role to "system"
|
|
136
|
+
for message in messages:
|
|
137
|
+
if message.role == "developer":
|
|
138
|
+
message.role = "system"
|
|
139
|
+
|
|
140
|
+
reasoning_content: str = ""
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
async for event in reasoning_agent.arun(input=messages, stream=True, stream_events=True):
|
|
144
|
+
if hasattr(event, "event"):
|
|
145
|
+
if event.event == RunEvent.run_content:
|
|
146
|
+
# Stream reasoning content as it arrives
|
|
147
|
+
if hasattr(event, "reasoning_content") and event.reasoning_content:
|
|
148
|
+
reasoning_content += event.reasoning_content
|
|
149
|
+
yield (event.reasoning_content, None)
|
|
150
|
+
elif event.event == RunEvent.run_completed:
|
|
151
|
+
pass
|
|
152
|
+
except Exception as e:
|
|
153
|
+
logger.warning(f"Reasoning error: {e}")
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
# Yield final message
|
|
157
|
+
if reasoning_content:
|
|
158
|
+
final_message = Message(
|
|
159
|
+
role="assistant",
|
|
160
|
+
content=f"<thinking>\n{reasoning_content}\n</thinking>",
|
|
161
|
+
reasoning_content=reasoning_content,
|
|
162
|
+
)
|
|
163
|
+
yield (None, final_message)
|
agno/reasoning/default.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from textwrap import dedent
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Callable, Dict, List, Literal, Optional, Union
|
|
5
5
|
|
|
6
6
|
from agno.models.base import Model
|
|
7
7
|
from agno.reasoning.step import ReasoningSteps
|
|
8
|
+
from agno.run.base import RunContext
|
|
8
9
|
from agno.tools import Toolkit
|
|
9
10
|
from agno.tools.function import Function
|
|
10
11
|
|
|
@@ -19,9 +20,7 @@ def get_default_reasoning_agent(
|
|
|
19
20
|
telemetry: bool = True,
|
|
20
21
|
debug_mode: bool = False,
|
|
21
22
|
debug_level: Literal[1, 2] = 1,
|
|
22
|
-
|
|
23
|
-
dependencies: Optional[Dict[str, Any]] = None,
|
|
24
|
-
metadata: Optional[Dict[str, Any]] = None,
|
|
23
|
+
run_context: Optional[RunContext] = None,
|
|
25
24
|
) -> Optional["Agent"]: # type: ignore # noqa: F821
|
|
26
25
|
from agno.agent import Agent
|
|
27
26
|
|
|
@@ -89,9 +88,9 @@ def get_default_reasoning_agent(
|
|
|
89
88
|
telemetry=telemetry,
|
|
90
89
|
debug_mode=debug_mode,
|
|
91
90
|
debug_level=debug_level,
|
|
92
|
-
session_state=session_state,
|
|
93
|
-
dependencies=dependencies,
|
|
94
|
-
metadata=metadata,
|
|
91
|
+
session_state=run_context.session_state if run_context else None,
|
|
92
|
+
dependencies=run_context.dependencies if run_context else None,
|
|
93
|
+
metadata=run_context.metadata if run_context else None,
|
|
95
94
|
)
|
|
96
95
|
|
|
97
96
|
return agent
|
agno/reasoning/gemini.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
|
|
@@ -13,9 +13,13 @@ def is_gemini_reasoning_model(reasoning_model: Model) -> bool:
|
|
|
13
13
|
if not is_gemini_class:
|
|
14
14
|
return False
|
|
15
15
|
|
|
16
|
-
# Check if it's a Gemini
|
|
16
|
+
# Check if it's a Gemini model with thinking support
|
|
17
|
+
# - Gemini 2.5+ models support thinking
|
|
18
|
+
# - Gemini 3+ models support thinking (including DeepThink variants)
|
|
17
19
|
model_id = reasoning_model.id.lower()
|
|
18
|
-
has_thinking_support =
|
|
20
|
+
has_thinking_support = (
|
|
21
|
+
"2.5" in model_id or "3.0" in model_id or "3.5" in model_id or "deepthink" in model_id or "gemini-3" in model_id
|
|
22
|
+
)
|
|
19
23
|
|
|
20
24
|
# Also check if thinking parameters are set
|
|
21
25
|
# Note: thinking_budget=0 explicitly disables thinking mode per Google's API docs
|
|
@@ -71,3 +75,83 @@ async def aget_gemini_reasoning(reasoning_agent: "Agent", messages: List[Message
|
|
|
71
75
|
return Message(
|
|
72
76
|
role="assistant", content=f"<thinking>\n{reasoning_content}\n</thinking>", reasoning_content=reasoning_content
|
|
73
77
|
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def get_gemini_reasoning_stream(
|
|
81
|
+
reasoning_agent: "Agent", # type: ignore # noqa: F821
|
|
82
|
+
messages: List[Message],
|
|
83
|
+
) -> Iterator[Tuple[Optional[str], Optional[Message]]]:
|
|
84
|
+
"""
|
|
85
|
+
Stream reasoning content from Gemini model.
|
|
86
|
+
|
|
87
|
+
Yields:
|
|
88
|
+
Tuple of (reasoning_content_delta, final_message)
|
|
89
|
+
- During streaming: (reasoning_content_delta, None)
|
|
90
|
+
- At the end: (None, final_message)
|
|
91
|
+
"""
|
|
92
|
+
from agno.run.agent import RunEvent
|
|
93
|
+
|
|
94
|
+
reasoning_content: str = ""
|
|
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
|
+
)
|
|
117
|
+
yield (None, final_message)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
async def aget_gemini_reasoning_stream(
|
|
121
|
+
reasoning_agent: "Agent", # type: ignore # noqa: F821
|
|
122
|
+
messages: List[Message],
|
|
123
|
+
) -> AsyncIterator[Tuple[Optional[str], Optional[Message]]]:
|
|
124
|
+
"""
|
|
125
|
+
Stream reasoning content from Gemini model asynchronously.
|
|
126
|
+
|
|
127
|
+
Yields:
|
|
128
|
+
Tuple of (reasoning_content_delta, final_message)
|
|
129
|
+
- During streaming: (reasoning_content_delta, None)
|
|
130
|
+
- At the end: (None, final_message)
|
|
131
|
+
"""
|
|
132
|
+
from agno.run.agent import RunEvent
|
|
133
|
+
|
|
134
|
+
reasoning_content: str = ""
|
|
135
|
+
|
|
136
|
+
try:
|
|
137
|
+
async for event in reasoning_agent.arun(input=messages, stream=True, stream_events=True):
|
|
138
|
+
if hasattr(event, "event"):
|
|
139
|
+
if event.event == RunEvent.run_content:
|
|
140
|
+
# Stream reasoning content as it arrives
|
|
141
|
+
if hasattr(event, "reasoning_content") and event.reasoning_content:
|
|
142
|
+
reasoning_content += event.reasoning_content
|
|
143
|
+
yield (event.reasoning_content, None)
|
|
144
|
+
elif event.event == RunEvent.run_completed:
|
|
145
|
+
pass
|
|
146
|
+
except Exception as e:
|
|
147
|
+
logger.warning(f"Reasoning error: {e}")
|
|
148
|
+
return
|
|
149
|
+
|
|
150
|
+
# Yield final message
|
|
151
|
+
if reasoning_content:
|
|
152
|
+
final_message = Message(
|
|
153
|
+
role="assistant",
|
|
154
|
+
content=f"<thinking>\n{reasoning_content}\n</thinking>",
|
|
155
|
+
reasoning_content=reasoning_content,
|
|
156
|
+
)
|
|
157
|
+
yield (None, final_message)
|
agno/reasoning/groq.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
|
|
@@ -8,7 +8,12 @@ from agno.utils.log import logger
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def is_groq_reasoning_model(reasoning_model: Model) -> bool:
|
|
11
|
-
return reasoning_model.__class__.__name__ == "Groq" and
|
|
11
|
+
return reasoning_model.__class__.__name__ == "Groq" and (
|
|
12
|
+
"deepseek" in reasoning_model.id.lower()
|
|
13
|
+
or "openai/gpt-oss-20b" in reasoning_model.id.lower()
|
|
14
|
+
or "openai/gpt-oss-120b" in reasoning_model.id.lower()
|
|
15
|
+
or "qwen/qwen3-32b" in reasoning_model.id.lower()
|
|
16
|
+
)
|
|
12
17
|
|
|
13
18
|
|
|
14
19
|
def get_groq_reasoning(reasoning_agent: "Agent", messages: List[Message]) -> Optional[Message]: # type: ignore # noqa: F821
|
|
@@ -69,3 +74,105 @@ async def aget_groq_reasoning(reasoning_agent: "Agent", messages: List[Message])
|
|
|
69
74
|
return Message(
|
|
70
75
|
role="assistant", content=f"<thinking>\n{reasoning_content}\n</thinking>", reasoning_content=reasoning_content
|
|
71
76
|
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def get_groq_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 Groq model.
|
|
85
|
+
|
|
86
|
+
For DeepSeek models on Groq, we use the main content output as reasoning content.
|
|
87
|
+
|
|
88
|
+
Yields:
|
|
89
|
+
Tuple of (reasoning_content_delta, final_message)
|
|
90
|
+
- During streaming: (reasoning_content_delta, None)
|
|
91
|
+
- At the end: (None, final_message)
|
|
92
|
+
"""
|
|
93
|
+
from agno.run.agent import RunEvent
|
|
94
|
+
|
|
95
|
+
# Update system message role to "system"
|
|
96
|
+
for message in messages:
|
|
97
|
+
if message.role == "developer":
|
|
98
|
+
message.role = "system"
|
|
99
|
+
|
|
100
|
+
reasoning_content: str = ""
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
for event in reasoning_agent.run(input=messages, stream=True, stream_events=True):
|
|
104
|
+
if hasattr(event, "event"):
|
|
105
|
+
if event.event == RunEvent.run_content:
|
|
106
|
+
# Check for reasoning_content attribute first (native reasoning)
|
|
107
|
+
if hasattr(event, "reasoning_content") and event.reasoning_content:
|
|
108
|
+
reasoning_content += event.reasoning_content
|
|
109
|
+
yield (event.reasoning_content, None)
|
|
110
|
+
# Use the main content as reasoning content
|
|
111
|
+
elif hasattr(event, "content") and event.content:
|
|
112
|
+
reasoning_content += event.content
|
|
113
|
+
yield (event.content, None)
|
|
114
|
+
elif event.event == RunEvent.run_completed:
|
|
115
|
+
pass
|
|
116
|
+
except Exception as e:
|
|
117
|
+
logger.warning(f"Reasoning error: {e}")
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
# Yield final message
|
|
121
|
+
if reasoning_content:
|
|
122
|
+
final_message = Message(
|
|
123
|
+
role="assistant",
|
|
124
|
+
content=f"<thinking>\n{reasoning_content}\n</thinking>",
|
|
125
|
+
reasoning_content=reasoning_content,
|
|
126
|
+
)
|
|
127
|
+
yield (None, final_message)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
async def aget_groq_reasoning_stream(
|
|
131
|
+
reasoning_agent: "Agent", # type: ignore # noqa: F821
|
|
132
|
+
messages: List[Message],
|
|
133
|
+
) -> AsyncIterator[Tuple[Optional[str], Optional[Message]]]:
|
|
134
|
+
"""
|
|
135
|
+
Stream reasoning content from Groq model asynchronously.
|
|
136
|
+
|
|
137
|
+
For DeepSeek models on Groq, we use the main content output as reasoning content.
|
|
138
|
+
|
|
139
|
+
Yields:
|
|
140
|
+
Tuple of (reasoning_content_delta, final_message)
|
|
141
|
+
- During streaming: (reasoning_content_delta, None)
|
|
142
|
+
- At the end: (None, final_message)
|
|
143
|
+
"""
|
|
144
|
+
from agno.run.agent import RunEvent
|
|
145
|
+
|
|
146
|
+
# Update system message role to "system"
|
|
147
|
+
for message in messages:
|
|
148
|
+
if message.role == "developer":
|
|
149
|
+
message.role = "system"
|
|
150
|
+
|
|
151
|
+
reasoning_content: str = ""
|
|
152
|
+
|
|
153
|
+
try:
|
|
154
|
+
async for event in reasoning_agent.arun(input=messages, stream=True, stream_events=True):
|
|
155
|
+
if hasattr(event, "event"):
|
|
156
|
+
if event.event == RunEvent.run_content:
|
|
157
|
+
# Check for reasoning_content attribute first (native reasoning)
|
|
158
|
+
if hasattr(event, "reasoning_content") and event.reasoning_content:
|
|
159
|
+
reasoning_content += event.reasoning_content
|
|
160
|
+
yield (event.reasoning_content, None)
|
|
161
|
+
# Use the main content as reasoning content
|
|
162
|
+
elif hasattr(event, "content") and event.content:
|
|
163
|
+
reasoning_content += event.content
|
|
164
|
+
yield (event.content, None)
|
|
165
|
+
elif event.event == RunEvent.run_completed:
|
|
166
|
+
pass
|
|
167
|
+
except Exception as e:
|
|
168
|
+
logger.warning(f"Reasoning error: {e}")
|
|
169
|
+
return
|
|
170
|
+
|
|
171
|
+
# Yield final message
|
|
172
|
+
if reasoning_content:
|
|
173
|
+
final_message = Message(
|
|
174
|
+
role="assistant",
|
|
175
|
+
content=f"<thinking>\n{reasoning_content}\n</thinking>",
|
|
176
|
+
reasoning_content=reasoning_content,
|
|
177
|
+
)
|
|
178
|
+
yield (None, final_message)
|
agno/reasoning/helpers.py
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import List, Literal, Optional
|
|
2
2
|
|
|
3
3
|
from agno.models.base import Model
|
|
4
4
|
from agno.models.message import Message
|
|
5
5
|
from agno.reasoning.step import NextAction, ReasoningStep
|
|
6
|
+
from agno.run.base import RunContext
|
|
6
7
|
from agno.run.messages import RunMessages
|
|
7
8
|
from agno.utils.log import logger
|
|
8
9
|
|
|
@@ -12,9 +13,7 @@ def get_reasoning_agent(
|
|
|
12
13
|
telemetry: bool = False,
|
|
13
14
|
debug_mode: bool = False,
|
|
14
15
|
debug_level: Literal[1, 2] = 1,
|
|
15
|
-
|
|
16
|
-
dependencies: Optional[Dict[str, Any]] = None,
|
|
17
|
-
metadata: Optional[Dict[str, Any]] = None,
|
|
16
|
+
run_context: Optional[RunContext] = None,
|
|
18
17
|
) -> "Agent": # type: ignore # noqa: F821
|
|
19
18
|
from agno.agent import Agent
|
|
20
19
|
|
|
@@ -23,9 +22,9 @@ def get_reasoning_agent(
|
|
|
23
22
|
telemetry=telemetry,
|
|
24
23
|
debug_mode=debug_mode,
|
|
25
24
|
debug_level=debug_level,
|
|
26
|
-
session_state=session_state,
|
|
27
|
-
dependencies=dependencies,
|
|
28
|
-
metadata=metadata,
|
|
25
|
+
session_state=run_context.session_state if run_context else None,
|
|
26
|
+
dependencies=run_context.dependencies if run_context else None,
|
|
27
|
+
metadata=run_context.metadata if run_context else None,
|
|
29
28
|
)
|
|
30
29
|
|
|
31
30
|
|