Skip to main content

TaskHandler

Trait TaskHandler 

Source
pub trait TaskHandler: Send + Sync {
    // Required method
    fn execute(
        &self,
        config: &Value,
    ) -> Pin<Box<dyn Future<Output = Result<(), SchedulerError>> + Send + '_>>;

    // Provided methods
    fn reads_external_content(&self) -> bool { ... }
    fn injects_agent_prompt(&self) -> bool { ... }
}
Expand description

Trait for types that can execute a scheduled task.

Implementations receive the per-task JSON configuration stored in ScheduledTask::config and return Ok(()) on success or a SchedulerError on failure. Failures are logged as warnings; the scheduler continues running and will retry on the next due tick.

Because async trait methods in Edition 2024 require returning a pinned boxed future for object safety, implementations must wrap their async work in Box::pin(async move { … }).

§Example

use std::future::Future;
use std::pin::Pin;
use zeph_scheduler::{SchedulerError, TaskHandler};

struct NoopHandler;

impl TaskHandler for NoopHandler {
    fn execute(
        &self,
        _config: &serde_json::Value,
    ) -> Pin<Box<dyn Future<Output = Result<(), SchedulerError>> + Send + '_>> {
        Box::pin(async move { Ok(()) })
    }
}

Required Methods§

Source

fn execute( &self, config: &Value, ) -> Pin<Box<dyn Future<Output = Result<(), SchedulerError>> + Send + '_>>

Execute the task with the provided configuration.

§Errors

Return SchedulerError::TaskFailed (or any other variant) to indicate that the task could not complete successfully. The error is logged but does not stop the scheduler.

Provided Methods§

Source

fn reads_external_content(&self) -> bool

Returns true when execute reads content that originates outside the scheduler’s own trusted config or in-process state — e.g. a network/HTTP response, an MCP tool result, a file loaded from a plugin-marketplace skill directory, or stored memory/graph facts that may themselves have been populated from such an external source.

RTW-A Mechanism 4 (capability attenuation, see crate::Scheduler::with_reentry_defense) reads this flag to decide whether the current tick counts as an external-read tick and should therefore suppress any custom-prompt injection dispatched later in the same tick.

Defaults to false so a handler must explicitly opt in — treating “unknown” as “safe” would silently exempt any handler that reads untrusted content from attenuation, defeating the purpose of the mechanism. Override this to true for any handler whose execute performs network I/O, reads MCP/tool output, reloads skills from disk, or surfaces previously stored content that may have originated from a less-trusted source.

§Examples
use std::future::Future;
use std::pin::Pin;
use zeph_scheduler::{SchedulerError, TaskHandler};

struct FetchesRemoteData;

impl TaskHandler for FetchesRemoteData {
    fn execute(
        &self,
        _config: &serde_json::Value,
    ) -> Pin<Box<dyn Future<Output = Result<(), SchedulerError>> + Send + '_>> {
        Box::pin(async move { Ok(()) })
    }

    fn reads_external_content(&self) -> bool {
        true
    }
}

assert!(FetchesRemoteData.reads_external_content());
Source

fn injects_agent_prompt(&self) -> bool

Returns true when execute injects an operator- or externally-supplied prompt into the agent loop (e.g. by sending it on a channel the agent reads as a new user message), as opposed to doing purely internal work (memory consolidation, a health probe, a network poll with no agent-facing output, etc.).

RTW-A Mechanism 4 (capability attenuation, see crate::Scheduler::with_reentry_defense) reads this flag on the scheduler’s normal handler-dispatch path (register_handler + execute_handler) to decide whether to suppress this handler’s execute for the remainder of a tick that already contained an external-read task (see reads_external_content). Without this declaration, a handler registered for TaskKind::Custom that injects prompts (e.g. the built-in CustomTaskHandler) would bypass Mechanism 4 entirely, since suppression only guarded the no-handler-registered fallback path.

Defaults to false for the same reason reads_external_content defaults to false: a handler must explicitly declare that it performs agent-facing prompt injection, so unrelated handlers (health checks, memory daemons, experiment runs) are never unnecessarily suppressed.

§Examples
use std::future::Future;
use std::pin::Pin;
use zeph_scheduler::{SchedulerError, TaskHandler};

struct InjectsAgentPrompt;

impl TaskHandler for InjectsAgentPrompt {
    fn execute(
        &self,
        _config: &serde_json::Value,
    ) -> Pin<Box<dyn Future<Output = Result<(), SchedulerError>> + Send + '_>> {
        Box::pin(async move { Ok(()) })
    }

    fn injects_agent_prompt(&self) -> bool {
        true
    }
}

assert!(InjectsAgentPrompt.injects_agent_prompt());

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§