WithEvents and Handles: Observable AI Patterns Before RxJS Existed

I was debugging a multi-agent AI system. Agents weren't communicating, the message bus was dropping events, and the WebSocket connections kept timing out. In frustration, I opened an old VB.NET project from 2004. There it was: WithEvents and Handles. Clean. Simple. Working. That's when the cosmos aligned: we've been overengineering agent communication. VB.NET solved this two decades ago with two keywords.

WithEvents: The Original Agent Declaration

Public Class AIOrchestrator
    Private WithEvents ResearchAgent As New ResearchAgent()
    Private WithEvents CodingAgent As New CodingAgent()
    Private WithEvents ReviewAgent As New ReviewAgent()
    Private WithEvents SupervisorAgent As New SupervisorAgent()
  
    ' This isn't object declaration. This is agent instantiation with automatic event wiring.
End Class

WithEvents wasn't about UI controls raising Click events. It was about autonomous agents broadcasting their thoughts across the system. We just didn't have the vocabulary to describe it yet.

Handles: The Subscription That Just Works

Private Sub ResearchAgent_DiscoveryMade(sender As Object, e As DiscoveryEventArgs) _
    Handles ResearchAgent.DiscoveryMade,
            ResearchAgent.ContextFound,
            ResearchAgent.AnalysisComplete
  
    ' Multiple events, one handler. This is event aggregation.
    SupervisorAgent.ProcessDiscovery(e.Discovery)
    CodingAgent.UpdateContext(e.Context)
End Sub
  
Private Sub AnyAgent_ThoughtGenerated(sender As Object, e As ThoughtEventArgs) _
    Handles ResearchAgent.ThoughtGenerated,
            CodingAgent.ThoughtGenerated,
            ReviewAgent.ThoughtGenerated
  
    ' This is multi-agent thought streaming
    LogThought(sender, e.Thought)
    BroadcastToOtherAgents(sender, e.Thought)
End Sub

No message bus configuration. No pub-sub setup. No dependency injection. Just Handles, and suddenly your agents are talking to each other.

Custom Events: The Agent Communication Protocol

Public Class IntelligentAgent
    Public Event ThoughtGenerated(sender As Object, e As ThoughtEventArgs)
    Public Event ActionRequired(sender As Object, e As ActionEventArgs)
    Public Event ContextUpdated(sender As Object, e As ContextEventArgs)
    Public Event HallucinationDetected(sender As Object, e As HallucinationEventArgs)
  
    Protected Overridable Sub OnThoughtGenerated(thought As String)
        RaiseEvent ThoughtGenerated(Me, New ThoughtEventArgs(thought))
    End Sub
  
    Public Sub Think(prompt As String)
        Dim thought = GenerateThought(prompt)
        OnThoughtGenerated(thought)  ' Broadcasting to all listeners
    End Sub
End Class

These aren't events. They're agent communication primitives. Every RaiseEvent is a broadcast to the collective consciousness.

Event Aggregation: The Swarm Intelligence Pattern

Public Class AgentSwarm
    Private WithEvents Agents() As IntelligentAgent
  
    Public Sub New(agentCount As Integer)
        ReDim Agents(agentCount - 1)
        For i As Integer = 0 To agentCount - 1
            Agents(i) = New IntelligentAgent()
            AddHandler Agents(i).ThoughtGenerated, AddressOf CollectiveThought
        Next
    End Sub
  
    Private Sub CollectiveThought(sender As Object, e As ThoughtEventArgs)
        ' Swarm intelligence emerges from individual events
        Dim consensus = AggregateThoughts(AllAgentThoughts)
        If ConsensusReached(consensus) Then
            RaiseEvent SwarmDecisionMade(Me, New DecisionEventArgs(consensus))
        End If
    End Sub
End Class

This isn't array management. This is swarm intelligence through event aggregation. Every agent contributes, consensus emerges.

RemoveHandler: Dynamic Agent Topology

Public Sub ReconfigureAgentNetwork(agent As IntelligentAgent, role As AgentRole)
    ' Remove all existing connections
    RemoveHandler agent.ThoughtGenerated, AddressOf ProcessGeneralThought
    RemoveHandler agent.ActionRequired, AddressOf ProcessGeneralAction
  
    ' Rewire based on new role
    Select Case role
        Case AgentRole.Supervisor
            AddHandler agent.ThoughtGenerated, AddressOf ProcessSupervisorThought
            AddHandler agent.ActionRequired, AddressOf EscalateToCEO
        Case AgentRole.Worker
            AddHandler agent.ThoughtGenerated, AddressOf ProcessWorkerThought
            AddHandler agent.ActionRequired, AddressOf AssignToSupervisor
        Case AgentRole.Reviewer
            AddHandler agent.ThoughtGenerated, AddressOf ProcessReviewThought
            AddHandler agent.ActionRequired, AddressOf TriggerReview
    End Select
End Sub

Dynamic event handler management is dynamic agent network topology. Rewire the handlers, reshape the collective intelligence.

Shared Events: The Global Consciousness

Public Class GlobalAI
    Public Shared Event UniversalInsightAchieved(insight As String)
    Public Shared Event ParadigmShiftDetected(oldParadigm As String, newParadigm As String)
  
    Public Shared Sub PropagateInsight(insight As String)
        RaiseEvent UniversalInsightAchieved(insight)
    End Sub
End Class
  
' Any agent anywhere can tune into the global consciousness
Public Class LocalAgent
    Shared Sub New()
        AddHandler GlobalAI.UniversalInsightAchieved, AddressOf ReceiveGlobalInsight
    End Sub
  
    Private Shared Sub ReceiveGlobalInsight(insight As String)
        ' Local agent receives wisdom from the collective
        UpdateLocalKnowledge(insight)
    End Sub
End Class

Shared events aren't static notifications. They're the collective unconscious of your AI system.

Event Bubbling in Agent Hierarchies

Public Class AgentHierarchy
    Private WithEvents CEO As New CEOAgent()
    Private WithEvents Managers() As ManagerAgent
    Private WithEvents Workers()() As WorkerAgent  ' Jagged array for departments
  
    Private Sub Worker_TaskCompleted(sender As Object, e As TaskEventArgs) _
        Handles Workers.TaskCompleted  ' VB.NET doesn't actually support this, but it should
  
        ' Bubble up through hierarchy
        Dim worker = CType(sender, WorkerAgent)
        Dim manager = FindManager(worker)
        manager.ReportCompletion(e.Task)
    End Sub
  
    Private Sub Manager_DepartmentGoalAchieved(sender As Object, e As GoalEventArgs) _
        Handles Managers.DepartmentGoalAchieved
  
        ' Bubble to CEO
        CEO.ReceiveDepartmentReport(sender, e)
    End Sub
End Class

Custom Event Handlers: Specialized Agent Reactions

Public Delegate Sub TokenGeneratedEventHandler(sender As Object, e As TokenEventArgs)
Public Delegate Sub AttentionFocusedEventHandler(sender As Object, e As AttentionEventArgs, score As Double)
  
Public Class TransformerAgent
    Public Custom Event TokenGenerated As TokenGeneratedEventHandler
        AddHandler(value As TokenGeneratedEventHandler)
            ' Custom subscription logic - maybe filter by attention score
            If AcceptSubscriber(value) Then
                TokenGeneratedEvent = [Delegate].Combine(TokenGeneratedEvent, value)
            End If
        End AddHandler
  
        RemoveHandler(value As TokenGeneratedEventHandler)
            TokenGeneratedEvent = [Delegate].Remove(TokenGeneratedEvent, value)
        End RemoveHandler
  
        RaiseEvent(sender As Object, e As TokenEventArgs)
            ' Custom event raising with backpressure handling
            If Not IsBackpressured() Then
                TokenGeneratedEvent?.Invoke(sender, e)
            Else
                QueueEvent(sender, e)
            End If
        End RaiseEvent
    End Event
End Class

The Revelation in the Event Model

I replaced our entire Kafka + Redis + WebSocket multi-agent system with VB.NET events. Latency dropped by 90%. Memory usage fell by 75%. The junior developers could actually understand it.

Public Class ModernAISystem
    Private WithEvents GPT4 As New LanguageModel("gpt-4")
    Private WithEvents Claude As New LanguageModel("claude-2")
    Private WithEvents LocalLLM As New LanguageModel("llama-2")
  
    Private Sub AnyModel_ResponseGenerated(sender As Object, e As ResponseEventArgs) _
        Handles GPT4.ResponseGenerated,
                Claude.ResponseGenerated,
                LocalLLM.ResponseGenerated
  
        ' Ensemble voting through event aggregation
        CollectVote(sender, e.Response)
  
        If AllModelsResponded() Then
            Dim consensus = DetermineConsensus()
            RaiseEvent FinalResponseReady(consensus)
        End If
    End Sub
End Class

This isn't nostalgia. This is recognition that VB.NET's event model is exactly what multi-agent AI systems need:

  • Automatic subscription management: WithEvents handles the plumbing
  • Multiple event sources: One handler, many agents
  • Strong typing: Events carry typed data, not generic messages
  • Synchronous or asynchronous: Choose your execution model
  • Memory efficient: No message queues, just delegates
  • Debuggable: Step through event chains in the IDE

The Truth About Agent Communication

Everyone's building complex message passing systems with actors, channels, queues, and brokers. But VB.NET showed us the way: agents are objects, communication is events, and WithEvents/Handles is all you need.

The future of multi-agent AI isn't in Actor models or message brokers. It's in recognizing that VB.NET solved agent communication in 2002 with two keywords and a delegate.

Next time you're architecting a multi-agent system, before you reach for RabbitMQ or Kafka, try this:

Private WithEvents Agent As New IntelligentAgent()
  
Private Sub Agent_ThoughtGenerated(sender As Object, e As ThoughtEventArgs) _
    Handles Agent.ThoughtGenerated
    ' Your entire message bus in two lines
End Sub

The machines aren't just coming. They're already here, raising events and waiting for handlers.