LLM agents have graduated from chatbots to autonomous operators capable of reading instructions, selecting tools, and executing email workflows. But a critical failure mode persists: the gap between interpreted intent and system necessity. As detailed in a recent DEV.to post by silviutech, agents frequently consult the wrong inbox, reuse addresses from previous runs, or attempt to send messages when they were only supposed to verify status. The solution isn't a longer prompt; it's a hard boundary between intent detection and action execution.

The Ambiguity of 'Confirm Signup'

To a human, "confirm user signup" is clear. To an agent with a generic email tool, it’s a trap. The request could mean searching for an existing message, triggering a new verification email, clicking a received link, or simply reporting that signup is complete. Without explicit state separation, an agent might skip from search to click, or resend an email because it failed to find evidence in time. This looks like a delivery failure, but it’s actually an interpretation error. The fix is defining three distinct states: intent_detected, action_authorized, and evidence_obtained, each tied to a unique execution ID.

Enforcing Contracts Over Prompts

The proposed architecture inserts a lightweight classification layer before any email tool is touched. Instead of relying on the LLM's probabilistic guessing, a small, verifiable object defines the scope: {"intent": "verify_existing_message", "run_id": "signup-1842", "can_send": false}. A policy engine then validates that the run_id exists, the mailbox belongs to that specific run, and the requested action is permitted. If can_send is false, no amount of prompt engineering can trick the agent into sending an email. This contract-based approach replaces the email box as a black hole with a dependency that has clear rules.

Typed States Prevent Hallucinated Fixes

Email tools for agents must return structured data, not free text. The minimum viable contract includes status codes like found, not_found, expired, forbidden, or timeout, alongside a stable message_id and observed_at timestamp. This prevents the agent from inventing explanations. A timeout doesn't mean the message doesn't exist; it means evidence is inconclusive. If the status is forbidden, the agent must stopβ€”retries just generate noise and risk mixing data. For testing, using isolated temporary mailboxes linked to a specific run_id and expiration date helps contain errors, but these fixtures are not security solutions for real identity.

The Isolation Test is the Real Proof

Validation isn't about whether the agent responded correctly, but whether every state transition left evidence. Developers should log the original request, the intent classification, the policy decision, the tool call, and the final termination reason. The most valuable test is isolation: running two nearly identical scenarios simultaneously to ensure one message can never satisfy the other's query. If this fails, don't tweak the prompt. Fix the tool's search scope or authorization policy. This pattern adds latency and complexity, but it transforms opaque agent failures into investigable incidents.

Key Takeaways

  • Separate intent detection, authorization, and evidence collection into distinct states with unique run IDs.
  • Use a policy engine to enforce hard limits (e.g., can_send: false) rather than relying on prompt instructions.
  • Email tools must return typed statuses (found, forbidden, timeout) to prevent agents from hallucinating solutions.
  • Implement isolation tests to ensure concurrent runs do not cross-contaminate email evidence.
  • Start by logging run_id and separating read/write permissions before adding complex classification models.

The Bottom Line

Stop trusting LLMs to interpret ambiguous actions on stateful systems. If your agent can send an email when it should only read one, you don't have a smart workflow; you have a liability. Boundaries are cheaper than post-mortems.