Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,24 @@ public async Task<bool> SendMessage(string agentId,

if (agent.Type == AgentType.Routing)
{
await routing.Context.Push(agent.Id, reason: "request started", updateLazyRouting: false);

// Check the routing mode
var states = _services.GetRequiredService<IConversationStateService>();
var routingMode = states.GetState(StateConst.ROUTING_MODE, agent.Mode ?? RoutingMode.Eager);
await routing.Context.Push(agent.Id, reason: "request started", updateLazyRouting: false);
var lazyRoutingAgentId = states.GetState(StateConst.LAZY_ROUTING_AGENT_ID);

if (routingMode == RoutingMode.Lazy)
if (routingMode == RoutingMode.Lazy && !string.IsNullOrEmpty(lazyRoutingAgentId))
{
message.CurrentAgentId = states.GetState(StateConst.LAZY_ROUTING_AGENT_ID, message.CurrentAgentId);
message.CurrentAgentId = lazyRoutingAgentId;
agent = await agentService.LoadAgent(message.CurrentAgentId);
await routing.Context.Push(message.CurrentAgentId, reason: "lazy routing", updateLazyRouting: false);
response = await routing.InstructDirect(agent, message, dialogs);
Comment on lines +92 to +95
Copy link
Contributor

Choose a reason for hiding this comment

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

Action required

1. loadagent null dereferenced 📘 Rule violation ⛯ Reliability

In lazy routing, the code calls agentService.LoadAgent and then passes agent to
routing.InstructDirect without guarding against LoadAgent returning null, which can cause a
NullReferenceException at runtime. This violates the requirement to add explicit null/empty guards
at provider/storage/state boundaries and return a safe fallback with logging.
Agent Prompt
## Issue description
`agentService.LoadAgent(message.CurrentAgentId)` can return `null`, but the lazy-routing path passes the possibly-null `agent` into `routing.InstructDirect`, which dereferences `agent` and can throw.

## Issue Context
`lazyRoutingAgentId` is loaded from conversation state and may be stale/invalid. `AgentService.LoadAgent` returns `null` when the ID is empty/invalid or the agent does not exist.

## Fix Focus Areas
- src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs[90-100]
- src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs[12-34]
- src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs[29-47]

## Implementation notes
- Load into a separate variable (e.g., `lazyAgent`) and check for null.
- If null, log a clear warning (without sensitive content) and fall back to a safe behavior (e.g., keep the current `agent` and call `InstructLoop`, or return a generic failure response).

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

}
else
{
response = await routing.InstructLoop(agent, message, dialogs);
}

response = await routing.InstructLoop(agent, message, dialogs);
}
else
{
Expand Down
10 changes: 3 additions & 7 deletions src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -299,14 +299,10 @@ private void UpdateLazyRoutingAgent(bool updateLazyRouting)

// Set next handling agent for lazy routing mode
var states = _services.GetRequiredService<IConversationStateService>();
var routingMode = states.GetState(StateConst.ROUTING_MODE, RoutingMode.Eager);
if (routingMode == RoutingMode.Lazy)
var agentId = GetCurrentAgentId();
if (agentId != BuiltInAgentId.Fallback)
{
var agentId = GetCurrentAgentId();
if (agentId != BuiltInAgentId.Fallback)
{
states.SetState(StateConst.LAZY_ROUTING_AGENT_ID, agentId);
}
states.SetState(StateConst.LAZY_ROUTING_AGENT_ID, agentId);
}
}
}
Loading