The agent conversation system was displaying duplicate responses when users sent messages to supervisor channels. This happened due to:
-
Dual Rendering Sources: Agent responses were displayed from both:
- New
agentConversationsstate (real-time streaming for supervisor mode) - Legacy database queries (
agentStepswithresponse/streamedContent)
- New
-
Non-Exclusive Rendering Logic: The ChatArea component rendered both sources simultaneously instead of prioritizing one over the other.
Implemented comprehensive fixes to ensure exclusive rendering and prevent database conflicts:
File: components/chat/chat-area.tsx
Changes:
- Modified rendering logic to be mutually exclusive
- Prioritize
agentConversationsstate over legacy agent step data - Only render legacy fallback when no conversation history exists
Before (Problematic):
{/* Both sections rendered simultaneously */}
{agentConversations[agent.index]?.map(...)}
{(!agentConversations[agent.index] || agentConversations[agent.index].length === 0) &&
(agent.response || agent.streamedContent) && (...)}After (Fixed):
{/* EXCLUSIVE RENDERING LOGIC */}
{agentConversations[agent.index] && agentConversations[agent.index].length > 0 ? (
// NEW: Supervisor mode conversation history
agentConversations[agent.index].map(...)
) : (
// LEGACY: Fallback only when no conversation history
(agent.response || agent.streamedContent) && (...)
)}Files Modified:
convex/mutations.tsapp/api/supervisor-interact/route.tslib/internal-agent-execution.ts
Core Enhancement: Added suppressResponseUpdate flag to updateAgentStep mutation:
// New parameter prevents response field updates in supervisor mode
suppressResponseUpdate: v.optional(v.boolean());
// Conditional update logic
if (args.response !== undefined && !args.suppressResponseUpdate)
updateData.response = args.response;Supervisor Route Changes:
// Before: Set response field causing dual rendering
await convex.mutation(api.mutations.updateAgentStep, {
stepId: agentStep._id,
response: agentResponse, // ❌ Caused dual rendering
isComplete: true,
isStreaming: false,
});
// After: Suppress response field updates
await convex.mutation(api.mutations.updateAgentStep, {
stepId: agentStep._id,
isComplete: true,
isStreaming: false,
suppressResponseUpdate: true, // ✅ Prevents dual rendering
});Additional Cleanup:
- Clear
streamedContentafter completion to prevent fallback rendering - Maintain conversation history as the single source of truth for supervisor mode
// Priority order for agent response display:
// 1. agentConversations (supervisor mode) - HIGHEST
// 2. agent.response/streamedContent (legacy) - FALLBACK
// 3. Loading states - LAST RESORT// Supervisor mode execution flow:
// 1. Stream directly to agentConversations
// 2. Update agent step status WITHOUT response field
// 3. Clear streamedContent to prevent legacy fallback
// 4. Maintain conversation history as source of truthThe suppressResponseUpdate flag enables different behaviors:
- Supervisor Mode: Response stored in conversation history only
- Regular Mode: Response stored in agent step for backward compatibility
-
Duplicate Response Prevention: ✅
- Agent responses no longer appear twice
- Exclusive rendering logic prevents overlap
-
Streaming Continuity: ✅
- Character-by-character streaming still works
- Real-time updates maintain smooth experience
-
Backward Compatibility: ✅
- Legacy agent executions still work normally
- Non-supervisor mode unchanged
-
State Consistency: ✅
- Database state properly managed
- No conflicting response sources
Agent Execution → Updates agent.response
↓
Frontend → Renders agentConversations + agent.response (DUPLICATE)
Supervisor Mode:
Agent Execution → Updates agentConversations only
↓
Frontend → Renders agentConversations only (EXCLUSIVE)
Regular Mode:
Agent Execution → Updates agent.response
↓
Frontend → Renders agent.response (LEGACY)
- Eliminates Duplicate Responses: No more double display issues
- Cleaner State Management: Single source of truth per mode
- Better Performance: Reduced rendering overhead
- Maintainable Code: Clear separation of concerns
- Future-Proof: Extensible for additional conversation modes
components/chat/chat-area.tsx- Exclusive rendering logicconvex/mutations.ts- suppressResponseUpdate flagapp/api/supervisor-interact/route.ts- Supervisor mode database handlinglib/internal-agent-execution.ts- Context-aware execution
This fix is backward compatible. Existing conversations will continue to work using the legacy fallback rendering system, while new supervisor interactions use the improved conversation history system.