pub trait Algorithm:
Send
+ Sync
+ 'static {
// Required methods
fn name(&self) -> &str;
fn create_run_task<'async_trait>(
self: Arc<Self>,
ctx: Context,
driver: Driver,
request: Request,
) -> Pin<Box<dyn Future<Output = Result<Response>> + Send + 'async_trait>>
where Self: 'async_trait;
// Provided methods
fn process_signals<'async_trait>(
self: Arc<Self>,
signals: Signals,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait { ... }
fn count_tokens_client(&self) -> Option<Arc<dyn RoutedLlmClient>> { ... }
fn count_tokens<'life0, 'async_trait>(
&'life0 self,
request: Request,
) -> Pin<Box<dyn Future<Output = Result<Value>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn run_stream(
self: Arc<Self>,
ctx: Context,
request: Request,
observer: Option<RunObserver>,
) -> StepStream { ... }
fn run<'async_trait>(
self: Arc<Self>,
ctx: Context,
request: Request,
) -> Pin<Box<dyn Future<Output = Result<(Vec<Arc<dyn Decision>>, Response)>> + Send + 'async_trait>>
where Self: 'async_trait { ... }
fn run_observed<'async_trait>(
self: Arc<Self>,
ctx: Context,
request: Request,
observer: Option<RunObserver>,
) -> Pin<Box<dyn Future<Output = Result<(Vec<Arc<dyn Decision>>, Response)>> + Send + 'async_trait>>
where Self: 'async_trait { ... }
}Expand description
An optimization strategy. Implement create_run_task;
callers drive it with the provided run (serve calls, get the answer)
or run_stream (drive the Step stream yourself).
Methods take self: Arc<Self>: one algorithm (Arc<dyn Algorithm>) is shared across
requests and run concurrently, so it owns its thread-safety and any shared state.
§Concurrency
A host may run the same algorithm concurrently for many requests. Implementations
must synchronize their own mutable shared state. Each call to run_stream
creates an independent Driver, so model-call promises and emitted Steps cannot
cross between runs.
§Observability
run_stream creates a libsy.run span, and each offloaded model
call creates a libsy.llm_call span. run additionally wraps calls it
serves through a target’s default client in libsy.client_call. Decisions and failures
are emitted through tracing; metrics use the global OpenTelemetry meter provider.
Required Methods§
Sourcefn name(&self) -> &str
fn name(&self) -> &str
Stable, low-cardinality name identifying this algorithm — the
algorithm attribute on every span, metric, and log line the crate
emits for its runs.
Sourcefn create_run_task<'async_trait>(
self: Arc<Self>,
ctx: Context,
driver: Driver,
request: Request,
) -> Pin<Box<dyn Future<Output = Result<Response>> + Send + 'async_trait>>where
Self: 'async_trait,
fn create_run_task<'async_trait>(
self: Arc<Self>,
ctx: Context,
driver: Driver,
request: Request,
) -> Pin<Box<dyn Future<Output = Result<Response>> + Send + 'async_trait>>where
Self: 'async_trait,
Run one request to completion: make model calls with Driver::call_llm_target,
publish Decisions with Driver::info, and return the final Response.
The method an algorithm implements; run / run_stream
drive it. ctx carries the request’s cross-cutting values (today: the
algorithm’s telemetry label in Context::values).
Provided Methods§
Sourcefn process_signals<'async_trait>(
self: Arc<Self>,
signals: Signals,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
fn process_signals<'async_trait>(
self: Arc<Self>,
signals: Signals,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
Feed the algorithm agentic-stack events (tool results, budgets, etc.). The
reference algorithms ignore signals; a stateful algorithm updates its own
(interior-mutable) state. Takes self: Arc<Self> like the other run methods.
Sourcefn count_tokens_client(&self) -> Option<Arc<dyn RoutedLlmClient>>
fn count_tokens_client(&self) -> Option<Arc<dyn RoutedLlmClient>>
The client count_tokens forwards to: the first of
this algorithm’s targets whose client can count tokens (an Anthropic
upstream). The default is None — an algorithm with no Anthropic target
does not support token counting.
CAVEAT: this picks the first Anthropic target, not a routed one — count_tokens is a direct passthrough, so it does not run the routing cascade. For a route with several Anthropic tiers “first” is arbitrary; choosing which tier count_tokens should reflect is deferred.
Sourcefn count_tokens<'life0, 'async_trait>(
&'life0 self,
request: Request,
) -> Pin<Box<dyn Future<Output = Result<Value>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn count_tokens<'life0, 'async_trait>(
&'life0 self,
request: Request,
) -> Pin<Box<dyn Future<Output = Result<Value>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Count the tokens request would use — a direct passthrough to this
algorithm’s Anthropic target (via
count_tokens_client), not a routed
call. Token counting is a pre-flight estimate with no routing decision,
so it deliberately bypasses the classifier cascade (which runs only for
completions via run). Returns the upstream’s JSON
verbatim. Errors when the algorithm has no Anthropic target.
Sourcefn run_stream(
self: Arc<Self>,
ctx: Context,
request: Request,
observer: Option<RunObserver>,
) -> StepStream
fn run_stream( self: Arc<Self>, ctx: Context, request: Request, observer: Option<RunObserver>, ) -> StepStream
Process a request to completion, returning a stream of Steps.
The consumer must fulfill every Step::CallLlm before the algorithm can
continue. The bounded step channel applies backpressure when the consumer is
not polling. A successful run ends with Step::ReturnToAgent; a failure is
emitted as an Err item. Dropping the stream aborts the spawned algorithm task.
Every invocation owns a separate Driver. observer, when present, receives
each completed model call and, after a successful routed run, its routing overhead.
Sourcefn run<'async_trait>(
self: Arc<Self>,
ctx: Context,
request: Request,
) -> Pin<Box<dyn Future<Output = Result<(Vec<Arc<dyn Decision>>, Response)>> + Send + 'async_trait>>where
Self: 'async_trait,
fn run<'async_trait>(
self: Arc<Self>,
ctx: Context,
request: Request,
) -> Pin<Box<dyn Future<Output = Result<(Vec<Arc<dyn Decision>>, Response)>> + Send + 'async_trait>>where
Self: 'async_trait,
Sourcefn run_observed<'async_trait>(
self: Arc<Self>,
ctx: Context,
request: Request,
observer: Option<RunObserver>,
) -> Pin<Box<dyn Future<Output = Result<(Vec<Arc<dyn Decision>>, Response)>> + Send + 'async_trait>>where
Self: 'async_trait,
fn run_observed<'async_trait>(
self: Arc<Self>,
ctx: Context,
request: Request,
observer: Option<RunObserver>,
) -> Pin<Box<dyn Future<Output = Result<(Vec<Arc<dyn Decision>>, Response)>> + Send + 'async_trait>>where
Self: 'async_trait,
Process a request to completion while reporting each model call to observer.