pub struct SkillService { /* private fields */ }Expand description
Central skill service coordinating storage + matching.
When a [GovernanceEngine] is attached, all skill mutations (updates,
prompt overlays) are gated through Cedar policy evaluation before
being applied. This enforces the Skill Mutation PEP for the
self-learning pipeline.
Implementations§
Source§impl SkillService
impl SkillService
Sourcepub fn new(
persistence: Option<Arc<dyn PersistenceLayer>>,
vector_matcher: Option<Arc<VectorMatcher>>,
) -> Self
pub fn new( persistence: Option<Arc<dyn PersistenceLayer>>, vector_matcher: Option<Arc<VectorMatcher>>, ) -> Self
Create a new skill service.
Sourcepub fn with_governance(self, engine: Arc<GovernanceEngine>) -> Self
pub fn with_governance(self, engine: Arc<GovernanceEngine>) -> Self
Attach a governance engine for Cedar policy enforcement on skill mutations.
When attached, update_skill checks is_skill_mutation_allowed before
applying changes. Without governance, all mutations are permitted.
Sourcepub fn add_provider(&mut self, provider: Arc<dyn SkillStorageProvider>)
pub fn add_provider(&mut self, provider: Arc<dyn SkillStorageProvider>)
Add a storage provider.
Sourcepub async fn register_builtins(&self, skills: Vec<Skill>)
pub async fn register_builtins(&self, skills: Vec<Skill>)
Register a batch of Skill { kind = Manifest, origin = Builtin } into
the registry, persisting each one when a database is configured.
Used at startup by the builtin-loader. Builtins are not written back
through the storage providers in Self::initialize — that would make
the pack a provider — but they DO reach the persistence layer, which is
what the admin UI, the REST API, and embedded hosts read.
This doc comment previously claimed “these skills are not persisted via
storage providers”, which read as not persisted at all and matched the
behaviour: nothing reached the database. See
super::registry::SkillRegistry::register for the defect.
Sourcepub async fn initialize(&self) -> Result<()>
pub async fn initialize(&self) -> Result<()>
Initialize the service by loading skills from all providers.
Sourcepub async fn get_skills(&self) -> Vec<Skill>
pub async fn get_skills(&self) -> Vec<Skill>
Get all skills from all providers.
Sourcepub async fn get_enabled_skills(&self) -> Vec<Skill>
pub async fn get_enabled_skills(&self) -> Vec<Skill>
Get only enabled skills.
Sourcepub async fn toggle_skill(&self, id: &str, enabled: bool) -> bool
pub async fn toggle_skill(&self, id: &str, enabled: bool) -> bool
Toggle a skill’s enabled state.
Sourcepub async fn set_scoped_enabled(
&self,
id: &str,
scope: SkillScope,
enabled: bool,
) -> bool
pub async fn set_scoped_enabled( &self, id: &str, scope: SkillScope, enabled: bool, ) -> bool
Set a durable enabled-state override at one scope.
Sourcepub async fn create_skill(&self, skill: Skill) -> Result<Skill>
pub async fn create_skill(&self, skill: Skill) -> Result<Skill>
Create a new skill dynamically via API.
Persists to the database (via the registry’s auto-persist path) and writes a SKILL.md file to the writable filesystem provider so the skill survives pod restarts.
Sourcepub async fn update_skill(
&self,
id: &str,
update: SkillUpdate,
) -> Result<Option<Skill>>
pub async fn update_skill( &self, id: &str, update: SkillUpdate, ) -> Result<Option<Skill>>
Update an existing skill by ID.
Returns Ok(None) if the skill does not exist.
When a [GovernanceEngine] is attached, the mutation is checked against
Cedar policies before being applied. The default environment is
"development" (all mutations permitted). Set PROMETHEUS_ENVIRONMENT
to "staging" or "production" for stricter enforcement.
Sourcepub async fn delete_skill_permanent(&self, id: &str) -> Result<bool>
pub async fn delete_skill_permanent(&self, id: &str) -> Result<bool>
Permanently delete a skill from the registry, database, and filesystem.
Skills with origin = Builtin are immutable; this method returns
Err(SystemSkillImmutable) for them so the API layer can map to 409.
Sourcepub async fn match_skills(
&self,
query: &str,
agent_id: Option<&str>,
) -> SkillMatchResult
pub async fn match_skills( &self, query: &str, agent_id: Option<&str>, ) -> SkillMatchResult
Match skills to a query without treating candidates as activations.
Sourcepub async fn match_skills_scoped(
&self,
query: &str,
agent_id: Option<&str>,
conversation_id: Option<&str>,
) -> SkillMatchResult
pub async fn match_skills_scoped( &self, query: &str, agent_id: Option<&str>, conversation_id: Option<&str>, ) -> SkillMatchResult
Match after resolving conversation > agent > global enabled state.
Sourcepub async fn get_agent_skill_ids(&self, agent_id: &str) -> Vec<String>
pub async fn get_agent_skill_ids(&self, agent_id: &str) -> Vec<String>
Get skill IDs explicitly enabled for an agent.
Sourcepub async fn set_agent_skills(&self, agent_id: &str, skill_ids: Vec<String>)
pub async fn set_agent_skills(&self, agent_id: &str, skill_ids: Vec<String>)
Replace an agent’s durable skill overrides using allowlist semantics.
Sourcepub async fn add_skill_to_agent(&self, agent_id: &str, skill_id: &str)
pub async fn add_skill_to_agent(&self, agent_id: &str, skill_id: &str)
Enable one skill for an agent.
Sourcepub async fn remove_skill_from_agent(&self, agent_id: &str, skill_id: &str)
pub async fn remove_skill_from_agent(&self, agent_id: &str, skill_id: &str)
Disable one skill for an agent.
Sourcepub async fn get_enabled_skills_for_agent(&self, agent_id: &str) -> Vec<Skill>
pub async fn get_enabled_skills_for_agent(&self, agent_id: &str) -> Vec<Skill>
Get skills enabled after resolving agent state over global state.
Sourcepub async fn get_matching_config(&self) -> SkillMatchingConfig
pub async fn get_matching_config(&self) -> SkillMatchingConfig
Get the current matching configuration.
Sourcepub async fn set_matching_config(&self, config: SkillMatchingConfig)
pub async fn set_matching_config(&self, config: SkillMatchingConfig)
Update the matching configuration.
Sourcepub fn registry(&self) -> &Arc<RwLock<SkillRegistry>> ⓘ
pub fn registry(&self) -> &Arc<RwLock<SkillRegistry>> ⓘ
Get access to the internal registry.
Sourcepub fn providers(&self) -> &[Arc<dyn SkillStorageProvider>]
pub fn providers(&self) -> &[Arc<dyn SkillStorageProvider>]
Get the list of registered providers.
Sourcepub async fn evolve_from_run(
&self,
run_id: &str,
tool_call_count: usize,
cfg: &SkillEvolutionConfig,
) -> Result<()>
pub async fn evolve_from_run( &self, run_id: &str, tool_call_count: usize, cfg: &SkillEvolutionConfig, ) -> Result<()>
Post-run skill evolution hook (Hermes learning cycle).
Called after a run completes when SkillEvolutionConfig::enabled is true
and the run performed at least min_tool_calls tool completions.
Currently this is a no-op stub — a future implementation will:
- Retrieve the run transcript / tool call log.
- Fire a reflection prompt via the configured LLM.
- Parse suggested skill CRUD operations from the response.
- Apply them subject to
allow_update/allow_deletionguards.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for SkillService
impl !RefUnwindSafe for SkillService
impl !UnwindSafe for SkillService
impl Send for SkillService
impl Sync for SkillService
impl Unpin for SkillService
impl UnsafeUnpin for SkillService
Blanket Implementations§
§impl<U> As for U
impl<U> As for U
§fn as_<T>(self) -> Twhere
T: CastFrom<U>,
U: Sized,
fn as_<T>(self) -> Twhere
T: CastFrom<U>,
U: Sized,
self to type T. The semantics of numeric casting with the as operator are followed, so <T as As>::as_::<U> can be used in the same way as T as U for numeric conversions. Read moreimpl<T> AsyncFriendly for T
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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
§impl<T> Conv for T
impl<T> Conv for T
impl<T> ErasedDestructor for Twhere
T: 'static,
§impl<T> FmtForward for T
impl<T> FmtForward for T
§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.§fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
§impl<T> FutureExt for T
impl<T> FutureExt for T
§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§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 more§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request§impl<L> LayerExt<L> for L
impl<L> LayerExt<L> for L
§fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
Layered].impl<T> MaybeSend for Twhere
T: Send,
impl<T> MaybeSend for Twhere
T: Send,
§impl<T> Message for T
impl<T> Message for T
§fn from_boxed(m: BoxedMessage) -> Result<Self, BoxedDowncastErr>
fn from_boxed(m: BoxedMessage) -> Result<Self, BoxedDowncastErr>
§fn box_message(self, pid: &ActorId) -> Result<BoxedMessage, BoxedDowncastErr>
fn box_message(self, pid: &ActorId) -> Result<BoxedMessage, BoxedDowncastErr>
§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read more§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read more§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.§impl<T> Pointable for T
impl<T> Pointable for T
§impl<T> Pointee for T
impl<T> Pointee for T
§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
§impl<F, T, S> SimdInto<T, S> for Fwhere
T: SimdFrom<F, S>,
S: Simd,
impl<F, T, S> SimdInto<T, S> for Fwhere
T: SimdFrom<F, S>,
S: Simd,
impl<T> State for T
§impl<T> Tap for T
impl<T> Tap for T
§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read more§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read more§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read more§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read more§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read more§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read more§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.