pub trait Module: Send + Sync {
Show 14 methods
// Required methods
fn input_schema(&self) -> Value;
fn output_schema(&self) -> Value;
fn description(&self) -> &str;
fn execute<'life0, 'life1, 'async_trait>(
&'life0 self,
inputs: Value,
ctx: &'life1 Context<Value>,
) -> Pin<Box<dyn Future<Output = Result<Value, ModuleError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
// Provided methods
fn stream(
&self,
_inputs: Value,
_ctx: &Context<Value>,
) -> Option<ChunkStream> { ... }
fn describe(&self) -> Value { ... }
fn preflight(
&self,
_inputs: &Value,
_ctx: Option<&Context<Value>>,
) -> Vec<String> { ... }
fn tags(&self) -> Vec<String> { ... }
fn preview(
&self,
_inputs: &Value,
_ctx: Option<&Context<Value>>,
) -> Option<PreviewResult> { ... }
fn on_load(&self) -> Result<(), ModuleError> { ... }
fn on_unload(&self) { ... }
fn on_suspend(&self) -> Option<Value> { ... }
fn on_resume(&self, _state: Value) { ... }
fn as_streaming(&self) -> Option<&dyn StreamingModule> { ... }
}Expand description
Core trait that all APCore modules must implement.
Required Methods§
Sourcefn input_schema(&self) -> Value
fn input_schema(&self) -> Value
Returns the JSON Schema describing this module’s input.
Sourcefn output_schema(&self) -> Value
fn output_schema(&self) -> Value
Returns the JSON Schema describing this module’s output.
Sourcefn description(&self) -> &str
fn description(&self) -> &str
Returns a human-readable description of this module.
Sourcefn execute<'life0, 'life1, 'async_trait>(
&'life0 self,
inputs: Value,
ctx: &'life1 Context<Value>,
) -> Pin<Box<dyn Future<Output = Result<Value, ModuleError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn execute<'life0, 'life1, 'async_trait>(
&'life0 self,
inputs: Value,
ctx: &'life1 Context<Value>,
) -> Pin<Box<dyn Future<Output = Result<Value, ModuleError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Execute the module with the given inputs and context.
Provided Methods§
Sourcefn stream(&self, _inputs: Value, _ctx: &Context<Value>) -> Option<ChunkStream>
fn stream(&self, _inputs: Value, _ctx: &Context<Value>) -> Option<ChunkStream>
Stream execution — returns an async Stream of output chunks.
Returns None if the module does not support streaming, signaling
the executor to fall back to execute(). Modules that support
streaming should override this to yield chunks incrementally — each
yield is delivered to the caller as soon as it is produced (true
streaming, no buffering).
Note: this method is not async even though it returns a stream.
The returned ChunkStream is itself an async iterator; constructing
it must be cheap and synchronous so the executor can wire it into
its own pipeline before the first chunk is awaited.
Validation contract: Executor::stream validates the module’s
merged output (all chunks deep-merged) against output_schema only
after the stream is exhausted (Phase 3). Individual chunks are not
validated as they are yielded. Callers performing incremental chunk
processing must tolerate receiving chunks that may not independently
satisfy output_schema. If per-chunk schema guarantees are required,
validate each chunk inside this method before yielding it.
Sourcefn describe(&self) -> Value
fn describe(&self) -> Value
Return a structured description of this module for AI/LLM consumption (spec §5.6).
Default: builds description from input_schema, output_schema, and description.
Sourcefn preflight(
&self,
_inputs: &Value,
_ctx: Option<&Context<Value>>,
) -> Vec<String>
fn preflight( &self, _inputs: &Value, _ctx: Option<&Context<Value>>, ) -> Vec<String>
Run preflight checks before execution.
Cross-language alignment (D11-009): mirrors apcore-python
Module.preflight(inputs, context) -> list[str] and apcore-typescript
preflight(inputs, context): string[]. Returns a list of advisory
warning strings; an empty list means “no concerns”. Modules that need
to gate execution should return errors from execute() directly
instead — preflight is non-fatal.
ctx is Option<&Context> because Executor::validate(module_id, inputs, ctx) accepts a None context for call-chain-free preflight
(matching Python’s executor.validate(..., context=None)); modules
that need a context for their checks must handle the None case.
The default implementation returns an empty warning list. Modules override this to inspect inputs (e.g., flag oversize payloads, warn on deprecated argument shapes) without rejecting the call.
Module-instance tags (D11-003).
Cross-language alignment with apcore-python (registry.py:1027,
reads getattr(mod, 'tags', [])) and apcore-typescript
(registry.ts:689, reads mod['tags']). Modules MAY override
this to participate in Registry::list(tags=...) filtering even
when registered without an explicit ModuleDescriptor (e.g. via
register_module(name, module)). The Rust Registry::list
unions these instance tags with descriptor.tags.
The default returns an empty Vec.
Sourcefn preview(
&self,
_inputs: &Value,
_ctx: Option<&Context<Value>>,
) -> Option<PreviewResult>
fn preview( &self, _inputs: &Value, _ctx: Option<&Context<Value>>, ) -> Option<PreviewResult>
Optional preview hook — return a structured prediction of changes.
Per the apcore RFC docs/spec/rfc-preview-method.md (Accepted, target
v0.21.0), called by Executor::validate() after the standard
validation pipeline has been processed. The default implementation
returns None (= the module declines to predict).
Contract (RFC §“Optional preview() method”):
- MUST NOT have side effects.
- Returning
None(or omitting the method) means “no predicted changes”. - Panicking is treated as advisory and does NOT fail validation; the
error is surfaced as a warning via the
module_previewcheck.
Cross-language alignment: matches apcore-python Module.preview and
apcore-typescript Module.preview?.
Sourcefn on_load(&self) -> Result<(), ModuleError>
fn on_load(&self) -> Result<(), ModuleError>
Called after the module is registered.
Returns Err to signal that the module failed to initialise; the
registry rolls back the insertion so no half-initialised module remains
registered. Aligns with apcore-python Registry._invoke_on_load.
Default: no-op (Ok(())).
Sourcefn on_suspend(&self) -> Option<Value>
fn on_suspend(&self) -> Option<Value>
Called before hot-reload to capture state. Returns state dict for on_resume().
Default: returns None (no state to preserve).
Sourcefn on_resume(&self, _state: Value)
fn on_resume(&self, _state: Value)
Called after hot-reload to restore state from on_suspend().
Default: no-op.
Sourcefn as_streaming(&self) -> Option<&dyn StreamingModule>
fn as_streaming(&self) -> Option<&dyn StreamingModule>
Return a typed streaming handle for adapter/bridge code.
Returns None for non-streaming modules (default). Streaming modules
override this to return Some(self).
Consistency invariant: Some(_) here IFF stream() returns Some(_).
Registry::register enforces this by returning
Err(StreamingInterfaceMismatch) when annotations.streaming = true
but as_streaming() returns None.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".