Semantic Triggers
Semantic triggers let you define concept-based rules that fire when an agent's queries, memories, or reasoning steps match a semantic concept. Unlike keyword-based rules, semantic triggers understand meaning -- a trigger for "financial risk" will fire on queries about "credit exposure" or "debt-to-equity ratios" even if the exact phrase "financial risk" never appears.
How It Works
Semantic triggers use a two-stage evaluation pipeline:
Agent activity (query, memory store, CoT step)
│
▼
Stage 1: Semantic Pre-Filter
- Embed the activity content
- Search the trigger concept index for top-K nearest concepts
- Fast: sub-millisecond for thousands of triggers
│
▼
Stage 2: Exact Cosine Verification
- Compute exact cosine similarity between activity and candidate concepts
- Apply threshold check (configurable per trigger)
- Eliminates false positives from ANN approximation
│
▼
Cooldown Check
- Has this trigger already fired recently for this agent?
- Debounce interval prevents alert storms
│
▼
Dispatch Action
- Webhook, AgentNotify, WriteEvent, or FlagForReview
This two-stage design gives you the speed of approximate search (handles thousands of triggers with negligible latency) combined with the precision of exact similarity computation.
Core Components
TriggerRegistry
The TriggerRegistry manages trigger definitions per organization:
- In-memory index: Trigger definitions keyed by trigger ID for fast lookup
- Vector index: One vector collection per organization containing embedded concept vectors
- CRUD operations: Register, update, delete, and list triggers
Each trigger definition includes:
| Field | Type | Description |
|---|---|---|
trigger_id | UUID | Unique identifier |
org_id | VARCHAR | Organization scope |
name | VARCHAR | Human-readable trigger name |
concept | TEXT | The semantic concept to match (natural language) |
threshold | FLOAT | Cosine similarity threshold (0.0 to 1.0) |
action | Action | What to do when the trigger fires |
cooldown_secs | INTEGER | Minimum seconds between firings per agent |
enabled | BOOLEAN | Whether the trigger is active |
created_at | TIMESTAMP | When the trigger was registered |
TriggerEvaluator
The TriggerEvaluator runs the two-stage evaluation pipeline:
-
ANN Pre-Filter: Embeds the input text and searches the organization's trigger concept index for the top-K nearest concept vectors (default K=10). This narrows thousands of triggers down to a small candidate set in under a millisecond.
-
Exact Cosine Verification: For each candidate, computes the exact cosine similarity between the input embedding and the trigger concept embedding. Only candidates above the trigger's configured
thresholdpass this stage. -
Cooldown Debounce: Checks a per-agent, per-trigger cooldown timer. If the trigger fired for this agent within the cooldown window, it is suppressed. This prevents alert storms when an agent repeatedly queries similar content.
TriggerDispatcher
When a trigger fires, the TriggerDispatcher executes one of four action types:
Webhook
Sends an HTTP POST to a configured URL with HMAC-SHA256 signature verification:
{
"trigger_id": "abc123",
"trigger_name": "Financial Risk Alert",
"agent_id": "analyst-agent",
"content": "SELECT credit_exposure, debt_ratio FROM ...",
"similarity_score": 0.91,
"fired_at": "2025-01-15T10:30:00Z"
}
The webhook payload is signed using HMAC-SHA256 with a per-trigger secret key. The signature is sent in the X-HatiData-Signature header, allowing receivers to verify authenticity.
AgentNotify
Delivers a notification to the agent's offline inbox (for agents that poll for notifications):
{
"notification_id": "def456",
"trigger_name": "Financial Risk Alert",
"message": "Your query matched a financial risk trigger. Please review before proceeding.",
"severity": "warning"
}
WriteEvent
Writes a structured event to the _hatidata_trigger_events table for later analysis:
{
"event_type": "trigger_fired",
"trigger_id": "abc123",
"agent_id": "analyst-agent",
"similarity_score": 0.91,
"content_excerpt": "SELECT credit_exposure..."
}
FlagForReview
Creates a review request in the control plane that a human administrator must approve or dismiss before the agent can proceed. This is the strongest action type and is intended for high-sensitivity triggers.
AgentNotifyInbox
The AgentNotifyInbox provides per-agent notification storage:
- Bounded VecDeque: Each agent has a fixed-size inbox (default: 100 notifications)
- TTL eviction: Notifications expire after a configurable time (default: 24 hours)
- FIFO overflow: When the inbox is full, the oldest notification is evicted
- Poll interface: Agents call
get_notifications(agent_id)to retrieve pending notifications
MCP Tools
register_trigger
Create a new semantic trigger.
Input:
{
"name": "PII Access Alert",
"concept": "queries accessing personally identifiable information such as social security numbers, email addresses, phone numbers, or home addresses",
"threshold": 0.82,
"action": {
"type": "webhook",
"url": "https://alerts.yourcompany.com/hatidata",
"secret": "whsec_your_webhook_secret"
},
"cooldown_secs": 300
}
Output:
{
"trigger_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "registered",
"concept_embedded": true
}
list_triggers
List all triggers for the current organization.
Input:
{
"enabled_only": true
}
Output:
[
{
"trigger_id": "a1b2c3d4-...",
"name": "PII Access Alert",
"concept": "queries accessing personally identifiable information...",
"threshold": 0.82,
"action_type": "webhook",
"cooldown_secs": 300,
"enabled": true,
"fire_count": 47,
"last_fired_at": "2025-01-15T09:22:00Z"
}
]
delete_trigger
Delete a trigger by ID.
Input:
{
"trigger_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
Removes the trigger from the trigger registry and its concept vector index.
test_trigger
Test whether a piece of text would fire any registered triggers, without actually dispatching actions.
Input:
{
"text": "SELECT ssn, email, phone FROM customers WHERE state = 'CA'"
}
Output:
{
"matches": [
{
"trigger_id": "a1b2c3d4-...",
"trigger_name": "PII Access Alert",
"similarity_score": 0.94,
"above_threshold": true,
"would_fire": true,
"cooldown_active": false
}
]
}
The test_trigger tool is useful for:
- Validating trigger concepts before deploying them
- Debugging why a trigger did or did not fire
- Tuning threshold values to balance precision and recall
Usage Examples
Python SDK
from hatidata_agent import HatiDataAgent
agent = HatiDataAgent(
host="your-org.proxy.hatidata.com",
agent_id="admin",
password="hd_live_your_api_key",
)
# Register a trigger
trigger = agent.register_trigger(
name="Cost Anomaly Detection",
concept="queries that scan very large tables without filters, potentially causing high compute costs",
threshold=0.80,
action={"type": "agent_notify", "severity": "warning"},
cooldown_secs=600,
)
print(f"Registered trigger: {trigger['trigger_id']}")
# Test a query against triggers
matches = agent.test_trigger(
text="SELECT * FROM events" # Full table scan, no WHERE clause
)
for match in matches["matches"]:
print(f"{match['trigger_name']}: {match['similarity_score']:.2f} (fire={match['would_fire']})")
# Check notifications
notifications = agent.get_notifications()
for note in notifications:
print(f"[{note['severity']}] {note['message']}")
Common Trigger Patterns
Data governance:
{
"name": "PII Column Access",
"concept": "accessing columns containing personal data like names, emails, SSNs, addresses, or phone numbers",
"threshold": 0.85,
"action": {"type": "flag_for_review"}
}
Cost control:
{
"name": "Expensive Query Pattern",
"concept": "queries with cross joins, full table scans without filters, or SELECT * on large tables",
"threshold": 0.78,
"action": {"type": "agent_notify", "severity": "warning"}
}
Compliance:
{
"name": "Financial Regulation",
"concept": "queries related to financial transactions, trading data, or regulatory reporting that may require compliance review",
"threshold": 0.80,
"action": {"type": "webhook", "url": "https://compliance.yourcompany.com/alerts"}
}
Anomaly detection:
{
"name": "Schema Discovery",
"concept": "queries exploring information_schema, pg_catalog, or system tables to discover database structure",
"threshold": 0.75,
"action": {"type": "write_event"}
}
Configuration
| Variable | Default | Description |
|---|---|---|
HATIDATA_TRIGGERS_ENABLED | true | Enable/disable semantic triggers |
HATIDATA_TRIGGER_ANN_TOP_K | 10 | Number of ANN candidates in pre-filter |
HATIDATA_TRIGGER_DEFAULT_COOLDOWN_SECS | 300 | Default cooldown between firings |
HATIDATA_TRIGGER_INBOX_SIZE | 100 | Max notifications per agent inbox |
HATIDATA_TRIGGER_INBOX_TTL_SECS | 86400 | Notification TTL (24 hours) |
HATIDATA_TRIGGER_WEBHOOK_TIMEOUT_SECS | 10 | Webhook HTTP request timeout |
Next Steps
- Agent Memory -- The memory system that triggers can monitor
- Chain-of-Thought Ledger -- Reasoning traces that triggers can evaluate
- State Branching -- Explore alternative paths when triggers fire