pub struct DelegationState {
pub beliefs: BTreeMap<String, BetaPosterior>,
pub config: DelegationConfig,
}Expand description
Per-session CADMAS-CTX sidecar.
Fields§
§beliefs: BTreeMap<String, BetaPosterior>Posteriors keyed by (agent_id, skill, bucket).
config: DelegationConfigRuntime configuration.
Implementations§
Source§impl DelegationState
impl DelegationState
Sourcepub fn with_config(config: DelegationConfig) -> Self
pub fn with_config(config: DelegationConfig) -> Self
Create a fresh state seeded with the supplied config.
Sourcepub fn enabled(&self) -> bool
pub fn enabled(&self) -> bool
Whether CADMAS-CTX routing is enabled for this session.
CODETETHER_DELEGATION_ENABLED overrides the persisted config when
present so operators can toggle the feature process-wide.
Sourcepub fn key(agent: &str, skill: &str, bucket: Bucket) -> String
pub fn key(agent: &str, skill: &str, bucket: Bucket) -> String
Serialise a (agent, skill, bucket) triple into the flat string
key used by the sidecar.
The encoding is "{agent}|{skill}|{difficulty}|{dependency}|{tool_use}"
where each bucket field is the canonical snake_case string from
Difficulty::as_str,
Dependency::as_str,
and ToolUse::as_str
— matching the serde representation. Persisted keys therefore stay
stable across enum reorderings / variant renames, because the
as_str methods are explicitly documented as never-renamed.
Sourcepub fn ensure(
&mut self,
agent: &str,
skill: &str,
bucket: Bucket,
c_self: f64,
) -> &mut BetaPosterior
pub fn ensure( &mut self, agent: &str, skill: &str, bucket: Bucket, c_self: f64, ) -> &mut BetaPosterior
Look up or create the posterior for (agent, skill, bucket)
using c_self as the weak-prior seed.
Sourcepub fn score(&self, agent: &str, skill: &str, bucket: Bucket) -> Option<f64>
pub fn score(&self, agent: &str, skill: &str, bucket: Bucket) -> Option<f64>
Current LCB score for (agent, skill, bucket); None when the
triple has never been seeded or updated.
Sourcepub fn update(
&mut self,
agent: &str,
skill: &str,
bucket: Bucket,
outcome: bool,
)
pub fn update( &mut self, agent: &str, skill: &str, bucket: Bucket, outcome: bool, )
Apply an observed outcome for (agent, skill, bucket).
Creates the posterior with a neutral c_self = 0.5 seed when
absent.
Sourcepub fn delegate_to<'a>(
&self,
local: &'a str,
peers: &'a [&'a str],
skill: &str,
bucket: Bucket,
) -> Option<&'a str>
pub fn delegate_to<'a>( &self, local: &'a str, peers: &'a [&'a str], skill: &str, bucket: Bucket, ) -> Option<&'a str>
Pick a peer to delegate to over local, or return None to
self-execute. Applies the margin rule score(peer) > score(local) + δ.
Sourcepub fn rank_candidates<'a>(
&self,
candidates: &'a [&'a str],
skill: &str,
bucket: Bucket,
) -> Option<&'a str>
pub fn rank_candidates<'a>( &self, candidates: &'a [&'a str], skill: &str, bucket: Bucket, ) -> Option<&'a str>
Rank candidates by their LCB score for (skill, bucket) and
return the best one, or None when the input is empty.
Unlike Self::delegate_to this does not honour a margin
δ — it’s the right primitive for orchestration sites that pick
“which executor runs this subtask” (src/swarm/orchestrator.rs
step 28), “which persona handles this handoff”
(src/ralph/ralph_loop.rs step 29), and “which autochat
persona goes next” (src/tui/app/autochat/ step 31) — there
is no “local” agent competing for the slot, so the margin rule
doesn’t apply.
Candidates with no posterior yet score 0.0 (conservative) and are only picked when every other candidate also has no data — i.e. the cold-start tie-break preserves the caller’s input order.
§Examples
use codetether_agent::session::delegation::{DelegationConfig, DelegationState};
use codetether_agent::session::delegation_skills::SWARM_DISPATCH;
use codetether_agent::session::relevance::{Bucket, Dependency, Difficulty, ToolUse};
let b = Bucket {
difficulty: Difficulty::Easy,
dependency: Dependency::Isolated,
tool_use: ToolUse::No,
};
let mut state = DelegationState::with_config(DelegationConfig::default());
// Cold start: no data → first candidate wins by input-order tie-break.
let pick = state.rank_candidates(&["shell_executor", "planner"], SWARM_DISPATCH, b);
assert_eq!(pick, Some("shell_executor"));Sourcepub fn shrink_cold_start(
&mut self,
agent: &str,
skill: &str,
bucket: Bucket,
neighbors: &[Bucket],
m_z: f64,
)
pub fn shrink_cold_start( &mut self, agent: &str, skill: &str, bucket: Bucket, neighbors: &[Bucket], m_z: f64, )
Pull at most m_z pseudo-counts from neighbors into the
posterior for (agent, skill, bucket) when that posterior has
no real observations yet.
Empirical-Bayes cold-start per CADMAS-CTX Section 3.6. Bounded
by m_z ≤ 2 so neighbour mass cannot drown real evidence.
Trait Implementations§
Source§impl Clone for DelegationState
impl Clone for DelegationState
Source§fn clone(&self) -> DelegationState
fn clone(&self) -> DelegationState
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for DelegationState
impl Debug for DelegationState
Source§impl Default for DelegationState
impl Default for DelegationState
Source§fn default() -> DelegationState
fn default() -> DelegationState
Source§impl<'de> Deserialize<'de> for DelegationState
impl<'de> Deserialize<'de> for DelegationState
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for DelegationState
impl RefUnwindSafe for DelegationState
impl Send for DelegationState
impl Sync for DelegationState
impl Unpin for DelegationState
impl UnsafeUnpin for DelegationState
impl UnwindSafe for DelegationState
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request