Just to expand on this a little... there are four possible events you might like to trap.
1) The agent is running.
2) The agent is not running.
3) The agent starts to run.
4) The agent stops running.
What you want to avoid is triggering a lot of unnecessary code usage every 0.25 seconds.

Depending on your particle set up you might be interested in 1) or 3).
2) isn't really interesting.
4) is the time to stop the particles if they persist (PSYS_SRC_MAX_AGE = 0).
3) and 4) are the basis of an AO.
A bare-bones example:
string lastAnim;
string lastAnimState;
default
{
state_entry()
{
llSetTimerEvent(0.25);
}
timer()
{
string curAnimState = llGetAnimation(llGetOwner());
if (curAnimState == "Running"

// agent is running
{
// run non-persistant particles
}
else // agent is not running
if (curAnimState != lastAnimState) // something changed since we last polled
{
if (curAnimState == "Running"

// agent starts to run
{
// start persistant particles
lastAnim = curAnimState;
}
else if (lastAnim != ""

// agent stops running
{
// stop particles
lastAnim = "";
}
lastAnimState = curAnimState;
}
}
}