Engineering

Semantic Triggers: Event-Driven Intelligence for AI Agents

HatiData Team8 min read

Why Agents Need Semantic Event Systems

Traditional event systems match on exact strings or pattern-based rules. An agent monitoring customer support tickets might set up a rule that fires when a ticket contains the word "outage." But customers do not always use the word "outage." They say "the system is down," "nothing is loading," "we cannot access the dashboard," or "everything stopped working." A keyword-based trigger misses all of these.

Semantic triggers solve this by matching on meaning rather than exact text. Instead of defining a trigger as "fire when the text contains 'outage'," you define it as "fire when the content is semantically similar to 'production system outage or service disruption.'" The trigger then matches any text that is conceptually close to that description, regardless of the specific words used.

HatiData implements semantic triggers as a first-class feature of the agent data warehouse. Triggers are registered with a concept description, a similarity threshold, and a dispatch action. Every time new content enters the system — whether through a memory store, a query result, or an explicit evaluation — it is checked against all registered triggers. When a match is found, the configured action fires automatically.

Two-Stage Evaluation Pipeline

The naive approach to semantic matching — compute cosine similarity between the input and every registered trigger — does not scale. With 1,000 triggers and a 768-dimensional embedding space, that is 1,000 dot-product computations per evaluation. At agent scale, with thousands of evaluations per minute, this becomes a bottleneck.

HatiData uses a two-stage evaluation pipeline that reduces the computational cost by orders of magnitude while maintaining accuracy.

Stage 1: Approximate Nearest Neighbor Pre-Filter

The first stage uses the vector search engine's approximate nearest neighbor (ANN) index to quickly identify candidate triggers. When a trigger is registered, its concept description is embedded and stored as a point in a vector collection specific to the organization.

When new content arrives for evaluation, HatiData embeds it and performs a top-K ANN search against the trigger collection. This returns the K most similar trigger concepts in sub-millisecond time, regardless of how many triggers are registered. The default K is 10, which means at most 10 triggers proceed to the second stage.

Stage 2: Exact Cosine Verification

The second stage computes exact cosine similarity between the input embedding and each candidate trigger's embedding. This eliminates false positives from the approximate first stage. Only triggers whose exact similarity exceeds the configured threshold are considered matches.

The two-stage approach means that evaluation time is O(log N) for the ANN lookup plus O(K) for exact verification, rather than O(N) for brute-force comparison. In practice, evaluating against 1,000 triggers takes under 50ms even on modest hardware.

Input Content
     |
     v
[Embed Input] ─── embedding service (384/768-dim)
     |
     v
[ANN Search] ─── top-K candidates (default K=10)
     |
     v
[Exact Cosine Verification] ─── filter by threshold
     |
     v
[Cooldown Check] ─── debounce recent fires
     |
     v
[Dispatch Action] ─── webhook / notify / event / flag

The Trigger Registry

The TriggerRegistry is the central data structure managing all active triggers. It uses a concurrent map for thread-safe access — multiple agents can register, modify, and evaluate triggers simultaneously without locking.

Each trigger entry contains:

  • trigger_id — A unique UUID assigned at registration time
  • concept — The natural language description of what this trigger matches
  • embedding — The vector representation of the concept, computed at registration time
  • threshold — The minimum cosine similarity for a match (default 0.75)
  • cooldown_seconds — Minimum time between consecutive fires for the same trigger (default 60)
  • action — What happens when the trigger fires
  • last_fired_at — Timestamp of the most recent fire, used for cooldown enforcement
  • org_id — The organization that owns this trigger, for multi-tenant isolation

Registering a trigger through the MCP tool:

json
{
  "tool": "register_trigger",
  "arguments": {
    "concept": "Customer reporting a production outage or critical service disruption",
    "threshold": 0.78,
    "cooldown_seconds": 300,
    "action": {
      "type": "webhook",
      "url": "https://hooks.slack.com/services/T00/B00/xxx",
      "headers": {
        "Content-Type": "application/json"
      }
    }
  }
}

Dispatcher Actions

When a trigger fires, the TriggerDispatcher executes the configured action. HatiData supports four dispatch action types, each designed for a different operational pattern.

Webhook (HMAC-SHA256 Signed)

The webhook action sends an HTTP POST to a configured URL with the trigger match details. The request body includes the trigger ID, the matched content, the similarity score, and a timestamp. Every webhook request is signed with HMAC-SHA256 using a per-trigger secret, allowing the receiver to verify authenticity.

json
{
  "trigger_id": "tr_8x9k2m",
  "concept": "Customer reporting a production outage",
  "matched_content": "Our dashboard has been completely unresponsive for 20 minutes",
  "similarity": 0.84,
  "timestamp": "2026-02-28T14:30:00Z",
  "signature": "sha256=a1b2c3d4..."
}

AgentNotify (Offline Inbox)

The AgentNotify action delivers the trigger match to an agent's notification inbox — a bounded, TTL-evicting queue per agent. This is designed for asynchronous agent architectures where the agent polls for notifications rather than receiving webhooks.

The inbox has a configurable maximum size (default 100 notifications) and TTL (default 24 hours). Older notifications are evicted when the inbox is full or when they expire. Agents retrieve notifications through the get_notifications MCP tool.

WriteEvent

The WriteEvent action inserts a structured event record into a designated events table in the query engine. This is useful for agents that process trigger matches as part of their regular query workflow — they can simply query the events table to find recent matches.

FlagForReview

The FlagForReview action creates a review item in the HatiData dashboard, visible to human operators. This is designed for high-stakes triggers where a human should validate the match before any automated action is taken. The review item includes the matched content, similarity score, and one-click approve/reject buttons.

Cooldown Debounce

In high-volume systems, the same conceptual event can appear multiple times in quick succession. A customer might send three messages about the same outage within a minute. Without debounce, the trigger would fire three times, sending three webhook notifications and creating noise.

HatiData implements cooldown debounce at the trigger level. Each trigger has a cooldown_seconds parameter that defines the minimum time between consecutive fires. When a trigger matches and fires, the dispatcher records the timestamp. Subsequent matches within the cooldown window are silently suppressed — the match is logged for audit purposes, but the action does not execute.

The cooldown state is tracked in-memory using atomic timestamps, so there is no database overhead for cooldown checks. The state is per-trigger, not global — different triggers can have different cooldown periods, and one trigger's cooldown does not affect another's.

Testing Triggers Without Side Effects

The test_trigger MCP tool evaluates an input against all registered triggers without firing any actions. This is essential for tuning thresholds — you can test candidate content and see which triggers would match, at what similarity scores, without sending webhooks or creating events.

json
{
  "tool": "test_trigger",
  "arguments": {
    "content": "The API has been returning 500 errors for the past hour"
  }
}

The response shows all matching triggers with their similarity scores:

json
{
  "matches": [
    {
      "trigger_id": "tr_8x9k2m",
      "concept": "Customer reporting a production outage",
      "similarity": 0.82,
      "would_fire": true,
      "cooldown_active": false
    },
    {
      "trigger_id": "tr_3j4n7p",
      "concept": "API performance degradation",
      "similarity": 0.79,
      "would_fire": true,
      "cooldown_active": false
    }
  ]
}

The would_fire field accounts for both the threshold check and cooldown state, so you see exactly what would happen if this content appeared in production.

Practical Patterns

Escalation Pipeline

Chain multiple triggers with increasing thresholds to create an escalation pipeline. A low-threshold trigger (0.65) logs the event. A medium-threshold trigger (0.75) notifies the assigned agent. A high-threshold trigger (0.85) pages a human operator.

Cross-Agent Coordination

Use WriteEvent triggers to create shared awareness between agents. When Agent A's trigger detects a relevant event, the WriteEvent inserts a record that Agent B's regular queries will pick up. This creates loose coupling between agents without direct communication.

Concept Drift Monitoring

Register triggers for concepts that should not appear in your data. If they start matching, it indicates a distribution shift in the content your agents are processing. For example, a trigger for "regulatory compliance violation" on an agent that should only handle routine customer requests.

Next Steps

Semantic triggers are most powerful when combined with other HatiData features. Use them with chain-of-thought logging to automatically flag reasoning chains that touch sensitive topics. Combine them with branch isolation to create exploratory branches when novel situations are detected. See the CrewAI semantic triggers cookbook for a complete multi-agent implementation.

Enjoyed this post?

Get notified when we publish new engineering deep-dives and product updates.

Ready to see the difference?

Run the free audit script in 5 minutes. Or start Shadow Mode and see HatiData run your actual workloads side-by-side.