Skip to content

Latest commit

 

History

History
592 lines (437 loc) · 24.9 KB

File metadata and controls

592 lines (437 loc) · 24.9 KB

DALI2 Examples Guide

This guide explains all included examples, how to run them, and the commands to test each feature.

DALI2 now supports DALI-compatible syntax — the same operators (:>, :<, ~/, </, ?/) and suffixes (E, I, A, N, P) as the original DALI framework. Each agent runs as a separate OS process.

Table of Contents


Running Examples

With Docker

Docker Compose starts Redis automatically — no separate install needed.

Linux / macOS:

# Default (agriculture example)
docker compose up --build

# Choose agent file
AGENT_FILE=examples/emergency.pl docker compose up --build

# Distributed (two nodes)
docker compose -f docker-compose.distributed.yml up --build

PowerShell (Windows):

# Default (agriculture example)
docker compose up --build

# Choose agent file
$env:AGENT_FILE="examples/emergency.pl"; docker compose up --build

# Distributed (two nodes)
docker compose -f docker-compose.distributed.yml up --build

Without Docker (SWI-Prolog + Redis)

Redis must be running before starting DALI2 (see Prerequisites in README).

# Step 1: Start Redis (if not already running)
redis-server                # local install
# or
docker run -d --name dali2-redis -p 6379:6379 redis:7-alpine   # via Docker

# Step 2: Start DALI2
swipl -l src/server.pl -g main -- 8080 examples/agriculture.pl

With run.bat (Windows)

run.bat

After starting, open http://localhost:8080 for the web UI.

Sending Events

You can send events to agents via the Web UI or the REST API.

Option A: Web UI (recommended for interactive testing)

  1. Open http://localhost:8080 in your browser
  2. In the Send Event panel (top-right area):
    • To: select the target agent from the dropdown (e.g. sensor)
    • Content: type the event term (e.g. read_temp(85))
    • Click Send
  3. Watch the Event Log panel (center) for real-time results
  4. Click any agent name in the Agents panel (left) to inspect its beliefs, past events, and goals

Tip: The "Send Event" panel uses the /api/send endpoint. For direct injection (bypasses normal message routing), use the REST API with /api/inject.

Option B: REST API (curl)

PowerShell (Windows):

# Send to a specific agent
curl.exe -X POST http://localhost:8080/api/send -H "Content-Type: application/json" -d "{""to"":""agent_name"",""content"":""event(args)""}"

# Inject directly into an agent's event queue
curl.exe -X POST http://localhost:8080/api/inject -H "Content-Type: application/json" -d "{""agent"":""agent_name"",""event"":""event(args)""}"

Note: On Windows, use curl.exe (not curl, which is a PowerShell alias). Use "" to escape double quotes inside double-quoted strings.

bash (Linux/Mac):

curl -X POST http://localhost:8080/api/send \
  -H "Content-Type: application/json" \
  -d '{"to":"agent_name","content":"event(args)"}'

1. Smart Agriculture

File: examples/agriculture.pl — Ported from the original DALI case study (dalia/case_study_smart_agriculture).

A precision agriculture system with 6 agents. Sensors validate readings via internal events (only abnormal readings are forwarded), the crop advisor decides actions (irrigate, reduce water, advisory), and the farmer receives notifications.

Agents

Agent Role
soil_sensor Receives soil readings, validates via internal events (alert vs normal)
weather_monitor Receives weather data, validates via internal events (risk vs normal)
crop_advisor Analyzes reports with AI, decides: irrigate / reduce_water / advisory
irrigation_controller Activates irrigation or reduces water supply
farmer_agent Receives advisories and status updates
logger Logs all events centrally

Features Demonstrated

  • Internal events — sensors validate readings (soil_alert_check, soil_normal_check, weather_risk_check, weather_normal_check)
  • Reactive rules (E suffix + :>) — all agents react to incoming events
  • Belief management — irrigation controller tracks active/reduced state per field
  • Multi-agent communication — message chains across 4+ agents
  • AI Oracle — crop_advisor uses AI for soil/weather analysis (if API key configured)
  • Conditional logic — crop_advisor branches on moisture/pH/temperature thresholds

Test Commands

# Start
swipl -l src/server.pl -g main -- 8080 examples/agriculture.pl

Via Web UI

Open http://localhost:8080 and use the Send Event panel:

Step To Content Expected
1 soil_sensor read_soil(25, 6.5, north_field) Low moisture → irrigate north_field
2 soil_sensor read_soil(85, 6.5, south_field) High moisture → reduce_water south_field
3 soil_sensor read_soil(50, 6.8, east_field) Normal soil → "SOIL NORMAL", no action
4 weather_monitor weather_update(40, 15, sunny) Drought risk → irrigate all_fields
5 weather_monitor weather_update(0, 60, clear) Frost warning → advisory to farmer

Click any agent in the Agents panel to inspect beliefs and past events.

Via REST API (curl)

# 1. Low moisture (25 < 30) → soil alert → irrigate
curl.exe -X POST http://localhost:8080/api/send -H "Content-Type: application/json" -d "{""to"":""soil_sensor"",""content"":""read_soil(25, 6.5, north_field)""}"

Expected flow:

soil_sensor: stores soil_state → internal soil_alert_check fires (25 < 30)
soil_sensor → crop_advisor: soil_report(25, 6.5, north_field)
crop_advisor: low moisture → irrigate
crop_advisor → irrigation_controller: irrigate(north_field)
crop_advisor → farmer_agent: advisory(irrigate, north_field)
irrigation_controller → farmer_agent: status(irrigating, north_field)
# 2. High moisture (85 > 80) → reduce water
curl.exe -X POST http://localhost:8080/api/send -H "Content-Type: application/json" -d "{""to"":""soil_sensor"",""content"":""read_soil(85, 6.5, south_field)""}"

Expected: soil alert → crop_advisor sends reduce_water(south_field) to irrigation controller.

# 3. Normal soil (50, 6.8) → no action
curl.exe -X POST http://localhost:8080/api/send -H "Content-Type: application/json" -d "{""to"":""soil_sensor"",""content"":""read_soil(50, 6.8, east_field)""}"

Expected: internal soil_normal_check fires — "SOIL NORMAL" logged, no report sent.

# 4. Drought risk (temp > 38) → emergency irrigation
curl.exe -X POST http://localhost:8080/api/send -H "Content-Type: application/json" -d "{""to"":""weather_monitor"",""content"":""weather_update(40, 15, sunny)""}"

Expected: weather risk → crop_advisor sends irrigate(all_fields) + advisory(drought_risk).

# 5. Frost warning (temp < 2)
curl.exe -X POST http://localhost:8080/api/send -H "Content-Type: application/json" -d "{""to"":""weather_monitor"",""content"":""weather_update(0, 60, clear)""}"

Expected: weather risk → advisory(frost_warning, all_fields) to farmer.

# 6. Check state
curl.exe http://localhost:8080/api/beliefs?agent=irrigation_controller
curl.exe http://localhost:8080/api/beliefs?agent=farmer_agent

2. Emergency Response

File: examples/emergency.pl — Ported from the original DALI emergency example (dalia/example).

A 9-agent emergency response system. The sensor validates alarms via internal events (real vs false alarm). The coordinator uses multi-step coordination with internal events: it waits for equipment from the manager before dispatching the responder. The communicator notifies person agents (mary, john).

Agents

Agent Role
sensor Detects events, validates alarms via internal events (real vs false)
coordinator Multi-step dispatch: AI analysis, waits for equipment, tracks done
manager Determines equipment (firetruck/bulldozer/respirator) based on type
evacuator Handles evacuation, reports back
responder Responds with equipment, reports back
communicator Notifies civilians (mary, john)
mary, john Person agents — receive evacuation messages
logger Logs all events

Features Demonstrated

  • Internal events — sensor: alarm validation (check_alarm, check_false_alarm); coordinator: dispatch_response (waits for equipment + location), check_done (waits for evacuated + responded)
  • Reactive rules (E suffix + :>) — full chain from detection to resolution
  • Belief management — coordinator tracks pending_location, equipment_ready, evacuated, responded
  • Multi-step coordination — responder is only dispatched after manager provides equipment
  • AI Oracle — coordinator analyzes emergency (if API key configured)

Test Commands

# Start
swipl -l src/server.pl -g main -- 8080 examples/emergency.pl

Via Web UI

Open http://localhost:8080 and use the Send Event panel:

Step To Content Expected
1 sensor sense(fire, building_a) Fire emergency → full multi-step response chain
2 sensor sense(wind, park) False alarm → "FALSE ALARM: wind at park"
3 sensor sense(earthquake, downtown) Earthquake → bulldozer selected, same chain

Click coordinator in the Agents panel to inspect beliefs (pending_location, equipment_ready, etc.).

Via REST API (curl)

# 1. Fire emergency — full multi-step flow
curl.exe -X POST http://localhost:8080/api/send -H "Content-Type: application/json" -d "{""to"":""sensor"",""content"":""sense(fire, building_a)""}"

Expected flow:

sensor: stores detected(fire, building_a) → internal check_alarm fires (fire ∈ alarm list)
sensor → coordinator: alarm(fire, building_a)
coordinator → evacuator + communicator + manager (dispatches all three)
manager: fire → firetruck → coordinator: equipped(firetruck)
communicator → mary + john: message(fire, building_a)
evacuator → coordinator: evacuated(building_a)
coordinator internal dispatch_response: location + equipment ready → responder: respond(firetruck, building_a)
responder → coordinator: responded(building_a)
coordinator internal check_done: evacuated + responded → "EMERGENCY RESOLVED"
# 2. False alarm — wind is not in [smoke, fire, earthquake]
curl.exe -X POST http://localhost:8080/api/send -H "Content-Type: application/json" -d "{""to"":""sensor"",""content"":""sense(wind, park)""}"

Expected: internal check_false_alarm fires — "FALSE ALARM: wind at park". No alarm sent to coordinator.

# 3. Earthquake (different equipment)
curl.exe -X POST http://localhost:8080/api/send -H "Content-Type: application/json" -d "{""to"":""sensor"",""content"":""sense(earthquake, downtown)""}"

Expected: manager selects bulldozer, same multi-step flow as fire.

# 4. Check state
curl.exe http://localhost:8080/api/beliefs?agent=coordinator
curl.exe http://localhost:8080/api/past?agent=coordinator

3. Feature Showcase

File: examples/showcase.pl

Demonstrates all 32 DALI2 features in a single file using DALI syntax (:>, :<, ~/, </, ?/, :~ operators and E/I/A suffixes). This is the comprehensive reference example that covers every rule type, DSL predicate, and advanced feature.

Agents

Agent Role Features Demonstrated
thermostat Temperature control Internal events (interval, change, trigger, between), constraints, on_change
sensor Sensor readings Periodic tasks, present events, learning, blackboard, past lifetime/remember
coordinator Central coordination Tell/told (priority queue), FIPA messages, multi-events, goals, residue goals, export past rules, proposal sending, AI oracle
logger Semantic logging Ontology (inline + external file), helpers, condition monitor
worker Task execution Action proposals (on_proposal), FIPA responses, export past rules, told rules

Features Tested

# Feature Agent How to Trigger
1 Reactive rules (E + :>) all Send events to agents
2 Internal event interval thermostat Automatic — temp_check fires every 5s (not every cycle)
3 Internal event change thermostat Send update_tempstartup_diagnostic counter resets
4 Internal event trigger thermostat cooling_monitor fires only when mode(cooling)
5 Internal event between thermostat work_hours_check fires in time window
6 Periodic tasks sensor Automatic — heartbeat every 15 seconds
7 Condition monitors (when) logger Warns when log volume > 10
8 Condition-action (:<) thermostat Edge-triggered when cooling mode activates
9 Present events sensor Blackboard data triggers environment observation
10 Multi-events (, + :>) coordinator Both sensor_data + alert → fires
11 Constraints thermostat Temperature > 50 triggers violation
12 Goals (achieve) sensor Calibration goal keeps trying until achieved
13 Goals (test) coordinator Tests if alerts received
14 Tell/told filtering coordinator Only accepts specific patterns; rejects others
15 Priority queue coordinator Messages sorted by told priority (200→10)
16 FIPA confirm coordinator→worker Inject send_confirm(system_ok) into coordinator
17 FIPA query_ref coordinator→worker Inject query_worker(status(_)) — auto-response
18 FIPA propose/accept coordinator→worker Inject request_analysis(data)
19 FIPA propose/reject coordinator→worker Inject test_reject
20 FIPA inform worker→coordinator Worker sends analysis results
21 Action proposals (on_proposal) worker Accepts/rejects proposals from coordinator
22 Past lifetime + remember sensor sensor_data expires after 30s, remembered 5min
23 Export past (~/) coordinator Alert + sensor_data consumed together
24 Export past NOT done (</) coordinator Fires if backup NOT done
25 Residue goals coordinator Inject start_residue_test then residue_resolved
26 External ontology file logger Loads test_ontology.pl on startup
27 Inline ontology logger log_event matches log_entry via same_as
28 Learning sensor read_temp(85) → learns overheating pattern
29 Actions (A suffix) worker analyze(Data) action definition
30 Helpers logger count_logs helper
31 Blackboard sensor Writes environment data
32 AI Oracle coordinator Emergency analysis (if API key configured)

Test Commands — Step by Step

# Start the showcase
swipl -l src/server.pl -g main -- 8080 examples/showcase.pl

Via Web UI

Open http://localhost:8080 and use the Send Event panel. Steps 1–2 use "Send" (message routing); steps 3–8 require the REST API with /api/inject (direct injection).

Step To Content Expected
1 sensor read_temp(85) Learning, blackboard, present event, cooling mode, constraint violation
2 sensor read_temp(90) Learned pattern warning, multi-event fires
10 thermostat update_temp(20) Constraint resolves, mode → idle

Steps 3–9 inject events directly into the coordinator (FIPA, export past, residue goals). Use curl or the REST API for these — see below.

Via REST API (curl)

Automatic behavior on startup:

  • thermostat: temp_check fires every 5s (interval), startup_diagnostic fires 3 times (change resets on temp change), work_hours_check fires (between), cooling_monitor does NOT fire (mode=idle)
  • sensor: periodic heartbeat, achieve goal sends calibration requests
  • coordinator: calibrates sensor, test goal checks for alerts
  • logger: loads test_ontology.pl (external ontology)
  • After ~4 seconds: sensor calibration achieved
# STEP 1: Send first temperature reading
# Triggers: learning, blackboard, present event, on_change, triggered internal,
#           constraint, export past (on_past), change condition reset, priority queue
curl.exe -X POST http://localhost:8080/api/send -H "Content-Type: application/json" -d "{""to"":""sensor"",""content"":""read_temp(85)""}"

Expected:

  • Sensor reads 85, writes to blackboard, sends sensor_data(85) to coordinator
  • Learning: learns overheating pattern
  • Present event: blackboard → thermostat gets update_temp(85)
  • On_change: "Cooling mode just activated" (edge-triggered, fires once)
  • Triggered internal: cooling_monitor starts firing (mode=cooling)
  • Constraint violated: 85 > 50 → emergency sent to coordinator
  • Change condition: thermostat's startup_diagnostic counter resets (current_temp changed)
  • Priority queue: coordinator processes emergency(200) before sensor_data(30)
  • Logger receives log_event → ontology matching works
# STEP 2: Send second reading (triggers learned pattern + multi-event + export past)
curl.exe -X POST http://localhost:8080/api/send -H "Content-Type: application/json" -d "{""to"":""sensor"",""content"":""read_temp(90)""}"

Expected:

  • Learned knowledge: "WARNING: Previously learned overheating pattern!"
  • Multi-event: sensor_data + alert both in past → fires
  • Export past (on_past): alert + sensor_data consumed from past memory
# STEP 3: Test FIPA confirm — coordinator sends confirm to worker
curl.exe -X POST http://localhost:8080/api/inject -H "Content-Type: application/json" -d "{""agent"":""coordinator"",""event"":""send_confirm(system_ok)""}"

Expected: Worker receives confirm(system_ok) → "Fact confirmed: system_ok" + "FIPA CONFIRM received"

# STEP 4: Test FIPA query_ref — coordinator queries worker's beliefs
curl.exe -X POST http://localhost:8080/api/inject -H "Content-Type: application/json" -d "{""agent"":""coordinator"",""event"":""query_worker(status(_))""}"

Expected: Worker auto-responds with inform(query_ref(status(_)), values([status(ready)])) → coordinator logs "FIPA QUERY_REF response"

# STEP 5: Test FIPA proposals — coordinator proposes to worker
curl.exe -X POST http://localhost:8080/api/inject -H "Content-Type: application/json" -d "{""agent"":""coordinator"",""event"":""request_analysis(sample_data)""}"

Expected: Worker accepts → executes analyze(sample_data) → sends inform(analysis_result, complete) back → coordinator logs "FIPA PROPOSAL ACCEPTED"

# STEP 6: Test rejected proposal
curl.exe -X POST http://localhost:8080/api/inject -H "Content-Type: application/json" -d "{""agent"":""coordinator"",""event"":""test_reject""}"

Expected: Worker rejects impossible_task → coordinator logs "FIPA PROPOSAL REJECTED"

# STEP 7: Test export past not_done
curl.exe -X POST http://localhost:8080/api/inject -H "Content-Type: application/json" -d "{""agent"":""coordinator"",""event"":""critical_data(important_backup)""}"

Expected: "EXPORT PAST NOT_DONE: backup NOT done! critical_data(important_backup) needs attention!"

# STEP 8: Test residue goals
curl.exe -X POST http://localhost:8080/api/inject -H "Content-Type: application/json" -d "{""agent"":""coordinator"",""event"":""start_residue_test""}"
# Wait 2 seconds, then inject the resolution:
curl.exe -X POST http://localhost:8080/api/inject -H "Content-Type: application/json" -d "{""agent"":""coordinator"",""event"":""residue_resolved""}"

Expected: "Goal queued as residue: has_past(residue_resolved)" → then "Residue goal achieved" after injection

# STEP 9: Test tell/told filtering — send an unaccepted message
curl.exe -X POST http://localhost:8080/api/send -H "Content-Type: application/json" -d "{""to"":""coordinator"",""content"":""unknown_message(test)""}"

Expected: Message rejected by told rule (coordinator only accepts defined patterns)

# STEP 10: Lower temperature — constraint resolves, change condition resets diagnostic
curl.exe -X POST http://localhost:8080/api/send -H "Content-Type: application/json" -d "{""to"":""thermostat"",""content"":""update_temp(20)""}"

Expected: Temperature drops to 20, constraint no longer violated, mode goes to idle, startup_diagnostic counter resets (change detected)

# STEP 11: Check all state via APIs
curl.exe http://localhost:8080/api/agents
curl.exe http://localhost:8080/api/beliefs?agent=thermostat
curl.exe http://localhost:8080/api/beliefs?agent=coordinator
curl.exe http://localhost:8080/api/beliefs?agent=worker
curl.exe http://localhost:8080/api/past?agent=coordinator
curl.exe http://localhost:8080/api/learned?agent=sensor
curl.exe http://localhost:8080/api/goals?agent=sensor
curl.exe http://localhost:8080/api/blackboard

4. Distributed Emergency

Files: examples/emergency_sensors.pl + examples/emergency_responders.pl

Two separate DALI2 nodes communicating via a shared Redis instance (star topology).

Node 1: Sensors (emergency_sensors.pl)

Agent Role
sensor Detects emergencies
logger Logs events

Node 2: Responders (emergency_responders.pl)

Agent Role
coordinator Dispatches responders
evacuator Handles evacuation
responder First response
communicator Public notification

Running Distributed

With Docker Compose (recommended):

docker compose -f docker-compose.distributed.yml up --build

This starts a shared Redis, sensors on port 8081, and responders on port 8082.

Manually (three terminals — Redis + two nodes):

# Terminal 1 — Start Redis
docker run -d --name dali2-redis -p 6379:6379 redis:7-alpine

# Terminal 2 — Sensor node on port 8080
swipl -l src/server.pl -g main -- 8080 examples/emergency_sensors.pl --name sensors

# Terminal 3 — Responder node on port 8081
swipl -l src/server.pl -g main -- 8081 examples/emergency_responders.pl --name responders

Both nodes connect to localhost:6379 automatically. No peer registration needed.

Test via Web UI:

Open http://localhost:8081 (sensors node) and use the Send Event panel:

To Content Expected
sensor detect(fire, building_a) Alarm crosses to node 2 → full response chain

Open http://localhost:8082 (responders node) to see coordinator, evacuator, and responder activity.

Test via REST API:

# Send emergency to sensor on node 1 (port 8081)
curl.exe -X POST http://localhost:8081/api/send -H "Content-Type: application/json" -d "{""to"":""sensor"",""content"":""detect(fire, building_a)""}"

Expected: sensor on node 1 sends alarm to coordinator on node 2 via Redis. Coordinator dispatches to evacuator, responder, communicator (all on node 2). Logger messages go back to node 1 via Redis.


API Quick Reference

Sending Events

# Send to a specific agent
curl.exe -X POST http://localhost:8080/api/send -H "Content-Type: application/json" -d "{""to"":""AGENT"",""content"":""EVENT(ARGS)""}"

# Inject directly into an agent's event queue
curl.exe -X POST http://localhost:8080/api/inject -H "Content-Type: application/json" -d "{""agent"":""AGENT"",""event"":""EVENT(ARGS)""}"

Querying State

# List all agents
curl.exe http://localhost:8080/api/agents

# Agent beliefs
curl.exe http://localhost:8080/api/beliefs?agent=AGENT

# Past events
curl.exe http://localhost:8080/api/past?agent=AGENT

# Learned patterns
curl.exe http://localhost:8080/api/learned?agent=AGENT

# Goal statuses
curl.exe http://localhost:8080/api/goals?agent=AGENT

# Blackboard contents
curl.exe http://localhost:8080/api/blackboard

# System logs
curl.exe http://localhost:8080/api/logs?agent=AGENT

# Cluster view (all agents across all nodes)
curl.exe http://localhost:8080/api/cluster

Agent Control

# Start/stop individual agents
curl.exe -X POST http://localhost:8080/api/start -H "Content-Type: application/json" -d "{""agent"":""AGENT""}"
curl.exe -X POST http://localhost:8080/api/stop -H "Content-Type: application/json" -d "{""agent"":""AGENT""}"

# Reload agent file
curl.exe -X POST http://localhost:8080/api/reload -H "Content-Type: application/json" -d "{""file"":""examples/showcase.pl""}"