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.