Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 37 additions & 7 deletions src/praisonai-agents/praisonaiagents/agent/router_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
from typing import Dict, List, Optional, Any, Union
from .agent import Agent
from ..llm.model_router import ModelRouter
from ..llm import LLM
from ..llm import LLM, TokenUsage
from ..trace.protocol import get_default_emitter

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -213,8 +214,8 @@ def _execute_with_model(
full_prompt = f"{context}\n\n{prompt}"

try:
# Execute with the selected model
response = llm_instance.get_response(
# Execute with the selected model, requesting token usage tracking
result = llm_instance.get_response(
prompt=full_prompt,
system_prompt=self._build_system_prompt(),
tools=tools,
Comment on lines +217 to 221
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Routeragent token_usage not persisted 📎 Requirement gap ✧ Quality

RouterAgent computes token_usage and an estimated_cost but only stores them in in-memory
model_usage_stats and emits them to trace metadata. It does not persist token/cost data into
chat_history or session metadata for later attribution.
Agent Prompt
## Issue description
RouterAgent tracks per-call `token_usage` and `estimated_cost` but does not persist these values into `chat_history` or session metadata, so later attribution/analysis is not possible.

## Issue Context
The project includes a SessionStore that supports per-message `metadata`, and compliance requires storing routing token/cost tracking in chat history or session metadata after routed interactions.

## Fix Focus Areas
- src/praisonai-agents/praisonaiagents/agent/router_agent.py[217-269]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Expand All @@ -225,16 +226,45 @@ def _execute_with_model(
agent_role=self.role,
agent_tools=[t.__name__ if hasattr(t, '__name__') else str(t) for t in (tools or [])],
execute_tool_fn=self.execute_tool if tools else None,
return_token_usage=True, # Request token usage information
**kwargs
)

# Extract response and token usage
if isinstance(result, tuple):
response, token_usage = result
else:
# Fallback for backward compatibility
response = result
token_usage = TokenUsage()

# Update usage statistics
self.model_usage_stats[model_name]['calls'] += 1
self.model_usage_stats[model_name]['tokens'] += token_usage.total_tokens

# Calculate and store cost estimate
model_info = self.model_router.get_model_info(model_name)
if model_info and token_usage.total_tokens > 0:
cost = self.model_router.estimate_cost(model_name, token_usage.total_tokens)
self.model_usage_stats[model_name]['cost'] += cost
Comment on lines +245 to +249
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Emit per-decision cost in the trace event.

estimated_cost is populated with the running model total after accumulation. From the second call onward, each trace event re-includes earlier spend, so any event-level aggregation will overcount. Emit the current call's cost here, or rename the field to cumulative_estimated_cost.

Suggested patch
-            model_info = self.model_router.get_model_info(model_name)
-            if model_info and token_usage.total_tokens > 0:
-                cost = self.model_router.estimate_cost(model_name, token_usage.total_tokens)
+            cost = 0.0
+            model_info = self.model_router.get_model_info(model_name)
+            if model_info and token_usage.total_tokens > 0:
+                cost = self.model_router.estimate_cost(model_name, token_usage.total_tokens)
                 self.model_usage_stats[model_name]['cost'] += cost
-                        'estimated_cost': self.model_usage_stats[model_name]['cost'],
+                        'estimated_cost': cost,
+                        'cumulative_estimated_cost': self.model_usage_stats[model_name]['cost'],

Also applies to: 251-263

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/praisonai-agents/praisonaiagents/agent/router_agent.py` around lines 245
- 249, The trace currently emits a cumulative estimated cost
(model_usage_stats[model_name]['cost']) after you add the current call's cost,
causing later events to include prior spend; change the trace payload to include
the per-call cost variable you compute (cost =
self.model_router.estimate_cost(...)) instead of the accumulated
model_usage_stats value, or if you intentionally want cumulative, rename the
emitted field to cumulative_estimated_cost; update references around
model_router.get_model_info, estimate_cost, model_usage_stats and where the
trace event is built so the event-level key holds the single-call cost (or the
renamed cumulative field) accordingly.


# TODO: Implement token tracking when LLM.get_response() is updated to return token usage
# The LLM response currently returns only text, but litellm provides usage info in:
# response.get("usage") with prompt_tokens, completion_tokens, and total_tokens
# This would require modifying the LLM class to return both text and metadata
# Emit token usage via trace system for observability
try:
trace_emitter = get_default_emitter()
trace_emitter.output(
content=f"RouterAgent routing decision completed",
agent_name=self.name,
metadata={
'selected_model': model_name,
'routing_strategy': self.routing_strategy,
'token_usage': token_usage.to_dict(),
'estimated_cost': self.model_usage_stats[model_name]['cost'],
'total_calls': self.model_usage_stats[model_name]['calls'],
}
)
except Exception as trace_error:
# Don't fail the request if tracing fails
logger.debug(f"Failed to emit trace event: {trace_error}")

return response

Expand Down
7 changes: 6 additions & 1 deletion src/praisonai-agents/praisonaiagents/llm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ def __getattr__(name):
from .rate_limiter import RateLimiter
_lazy_cache[name] = RateLimiter
return RateLimiter
elif name == "TokenUsage":
from .llm import TokenUsage
_lazy_cache[name] = TokenUsage
return TokenUsage

raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

Expand All @@ -117,5 +121,6 @@ def __getattr__(name):
"ModelProfile",
"TaskComplexity",
"create_routing_agent",
"RateLimiter"
"RateLimiter",
"TokenUsage"
]
Loading
Loading