Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 47 additions & 31 deletions src/openhuman/skills/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::path::Path;
use serde::{Deserialize, Serialize};

use crate::openhuman::agent::harness::definition::{AgentDefinition, PromptSource};
use crate::openhuman::skills::WorkflowScope;
use crate::openhuman::skills::{Workflow, WorkflowScope};

/// One declared input — a parameter the skill needs, with a human description.
/// `required` inputs must be supplied at run time; `kind` is an optional type
Expand Down Expand Up @@ -172,10 +172,35 @@ pub fn load_workflows_with_profile(
workspace_dir: &Path,
profile_skills_root: Option<&Path>,
) -> Vec<WorkflowDefinition> {
// Prune any legacy bundled skills an older build left behind so discover's
// legacy scan no longer surfaces them (idempotent).
definitions_from_discovered(&discover_all(workspace_dir, profile_skills_root))
}

/// Prune legacy bundled skills, then enumerate every installed skill across all
/// roots (deduped + scope-prioritised) via the same discovery the create/list
/// path uses. Returns the lightweight discovered entries **without** parsing
/// each one's definition — callers that need only a slug/name/scope (e.g. the
/// display-name fallback in [`get_workflow_with_profile`]) can reuse this list
/// instead of walking the roots again.
///
/// The prune runs **before** discovery so its legacy scan no longer surfaces
/// the pruned skills (idempotent).
fn discover_all(workspace_dir: &Path, profile_skills_root: Option<&Path>) -> Vec<Workflow> {
prune_legacy_default_workflows(workspace_dir);
let home = dirs::home_dir();
let trusted = super::ops_discover::is_workspace_trusted(workspace_dir);
super::ops_discover::discover_workflows_with_profile(
home.as_deref(),
Some(workspace_dir),
profile_skills_root,
trusted,
)
}

/// Parse a [`WorkflowDefinition`] for each already-discovered skill, prepended
/// by the built-in agents. Split out from [`load_workflows_with_profile`] so a
/// single [`discover_all`] walk can feed both the parsed list and a slug/name
/// lookup without re-discovering.
fn definitions_from_discovered(discovered: &[Workflow]) -> Vec<WorkflowDefinition> {
let mut workflows: Vec<WorkflowDefinition> = Vec::new();

if let Ok(builtins) = crate::openhuman::agent::registry::agents::load_builtins() {
Expand All @@ -188,16 +213,7 @@ pub fn load_workflows_with_profile(
}
}

// Enumerate across all roots (deduped + scope-prioritised) via the same
// discovery the create/list path uses, then load each one's definition.
let home = dirs::home_dir();
let trusted = super::ops_discover::is_workspace_trusted(workspace_dir);
for wf in super::ops_discover::discover_workflows_with_profile(
home.as_deref(),
Some(workspace_dir),
profile_skills_root,
trusted,
) {
for wf in discovered {
let Some(skill_md) = wf.location.as_ref() else {
continue;
};
Expand Down Expand Up @@ -287,7 +303,13 @@ pub fn get_workflow_with_profile(
id: &str,
profile_skills_root: Option<&Path>,
) -> Option<WorkflowDefinition> {
let workflows = load_workflows_with_profile(workspace_dir, profile_skills_root);
// Discover once; both the parsed-definition lookup and the display-name
// fallback below derive from this single walk. Previously each call
// discovered the roots twice — once inside `load_workflows_with_profile`
// and again for the name fallback.
let discovered = discover_all(workspace_dir, profile_skills_root);
let workflows = definitions_from_discovered(&discovered);

// Built-ins are prepended and discovered workflows follow them. Search in
// reverse so the scope-resolved discovered entry (profile wins over global)
// also wins over a built-in with the same runnable id.
Expand All @@ -300,23 +322,17 @@ pub fn get_workflow_with_profile(
// a private workflow admitted by the profile-local allow set can actually
// be described and run. Keep the legacy profile-less lookup id-only: global
// display names have never been runnable ids and may collide with builtins.
let home = dirs::home_dir();
let trusted = super::ops_discover::is_workspace_trusted(workspace_dir);
let slug = super::ops_discover::discover_workflows_with_profile(
home.as_deref(),
Some(workspace_dir),
profile_skills_root,
trusted,
)
.into_iter()
.find(|workflow| workflow.scope == WorkflowScope::Profile && workflow.name == id)
.map(|workflow| {
if workflow.dir_name.is_empty() {
workflow.name
} else {
workflow.dir_name
}
})?;
// Reuse the discovery above rather than walking the roots a second time.
let slug = discovered
.iter()
.find(|workflow| workflow.scope == WorkflowScope::Profile && workflow.name == id)
.map(|workflow| {
if workflow.dir_name.is_empty() {
workflow.name.clone()
} else {
workflow.dir_name.clone()
}
})?;

workflows
.into_iter()
Expand Down
Loading