Some checks failed
Build and Deploy Docs / build-and-deploy (push) Has been cancelled
- Created logs/ structure (sessions, operations, incidents) - Added session-start/log/end scripts - Installed Git hooks for auto-logging commits/pushes - Added shell integration for zsh - Created CHANGELOG.md - Documented today's session (2026-01-10)
Agent Filter Service
Security & routing layer for DAARION agents in Messenger
Purpose
Agent Filter decides when and which agents should respond to messages based on configurable rules.
Features
- Loop Prevention: Blocks agent→agent message loops
- Quiet Hours: Modifies agent behavior during specified times (23:00–07:00)
- Agent Mapping: Maps microDAOs to default agents
- Channel Permissions: Respects allowed/disabled agents per channel
- NATS Integration: Subscribes to message events, publishes filter decisions
Architecture
messaging.message.created (NATS)
↓
agent-filter: Apply Rules
↓
agent.filter.decision (NATS)
Rules
1. Loop Prevention
- Rule: Block messages from agents
- Reason: Prevent infinite agent→agent conversations
2. Quiet Hours
- Time: 23:00 – 07:00 (configurable in
config.yaml) - Effect: Adds rewrite prompt for concise responses
- Purpose: Reduce agent activity during off-hours
3. Agent Mapping
- Default Agents: Defined per microDAO in
config.yaml - Channel Override: Channels can specify
allowed_agents - Fallback: If no agent found, deny
4. Disabled Agents
- Check: Ensures target agent is not in
disabled_agentslist - Source: From channel context
API
Health Check
GET /health
Response:
{
"status": "ok",
"service": "agent-filter",
"version": "1.0.0",
"nats_connected": true
}
Test Filtering (Manual)
POST /internal/agent-filter/test
Content-Type: application/json
{
"channel_id": "test-channel-id",
"matrix_event_id": "$event123:matrix.daarion.city",
"sender_id": "user:93",
"sender_type": "human",
"microdao_id": "microdao:daarion",
"created_at": "2025-11-24T12:00:00Z"
}
Response:
{
"channel_id": "test-channel-id",
"matrix_event_id": "$event123:matrix.daarion.city",
"microdao_id": "microdao:daarion",
"decision": "allow",
"target_agent_id": "agent:sofia"
}
Configuration
File: config.yaml
nats:
servers: ["nats://nats:4222"]
messaging_subject: "messaging.message.created"
decision_subject: "agent.filter.decision"
rules:
quiet_hours:
start: "23:00"
end: "07:00"
default_agents:
"microdao:daarion": "agent:sofia"
"microdao:7": "agent:sofia"
Environment Variables
MESSAGING_SERVICE_URL: URL of messaging-service (default:http://messaging-service:7004)NATS_URL: NATS server URL (default:nats://nats:4222)
Running Locally
Install Dependencies
pip install -r requirements.txt
Run Service
uvicorn main:app --reload --port 7005
Test
# Health check
curl http://localhost:7005/health
# Test filtering
curl -X POST http://localhost:7005/internal/agent-filter/test \
-H "Content-Type: application/json" \
-d '{
"channel_id": "test-123",
"matrix_event_id": "$test:matrix.daarion.city",
"sender_id": "user:1",
"sender_type": "human",
"microdao_id": "microdao:daarion",
"created_at": "2025-11-24T12:00:00Z"
}'
Docker
Build
docker build -t daarion/agent-filter:latest .
Run
docker run -p 7005:7005 \
-e MESSAGING_SERVICE_URL=http://messaging-service:7004 \
-e NATS_URL=nats://nats:4222 \
daarion/agent-filter:latest
NATS Events
Subscribes To
- Subject:
messaging.message.created - Payload:
MessageCreatedEvent
{
"channel_id": "uuid",
"message_id": "uuid",
"matrix_event_id": "$event:server",
"sender_id": "user:X or agent:Y",
"sender_type": "human | agent",
"microdao_id": "microdao:X",
"created_at": "2025-11-24T12:00:00Z"
}
Publishes To
- Subject:
agent.filter.decision - Payload:
FilterDecision
{
"channel_id": "uuid",
"message_id": "uuid",
"matrix_event_id": "$event:server",
"microdao_id": "microdao:X",
"decision": "allow | deny | modify",
"target_agent_id": "agent:sofia",
"rewrite_prompt": "Optional prompt modification"
}
Development
Adding New Rules
Edit rules.py:
def decide(self, event: MessageCreatedEvent, ctx: FilterContext) -> FilterDecision:
# Add your rule here
if some_condition:
return FilterDecision(
decision="deny",
# ... other fields
)
# Continue with existing rules
...
Testing Rules
Use the test endpoint:
curl -X POST http://localhost:7005/internal/agent-filter/test \
-H "Content-Type: application/json" \
-d @test_event.json
Monitoring
Logs
# Docker
docker logs -f agent-filter
# Look for:
# ✅ Connected to NATS
# ✅ Subscribed to messaging.message.created
# 📨 Received message.created event
# 🎯 Decision: allow/deny/modify
# ✅ Published decision to NATS
Metrics (Future)
- Total messages processed
- Decisions per type (allow/deny/modify)
- Average processing time
- NATS connection status
Troubleshooting
NATS Not Connected
⚠️ NATS not available: [error]
⚠️ Running in test mode (HTTP only)
Solution: Check NATS is running and accessible:
docker ps | grep nats
docker logs nats
No Decisions Published
Check:
- Is messaging-service publishing events?
- Is channel context endpoint working?
- Are rules correctly configured?
# Test channel context
curl http://localhost:7004/internal/messaging/channels/{channel_id}/context
Always Denying
Common causes:
- Sender is agent (loop prevention)
- No target agent found
- Target agent is disabled
- Channel context not accessible
Debug: Use test endpoint and check logs
Future Enhancements
- Keyword-based triggers ("@sofia", "@assistant")
- Per-user permissions
- Rate limiting per agent
- Sentiment analysis for filtering
- ML-based spam detection
- Custom rule scripting (Lua/Python)
Version
Current: 1.0.0
Status: Production Ready
Last Updated: 2025-11-24