use everruns_core::capabilities::{
AgentCapabilityConfig, BACKGROUND_EXECUTION_CAPABILITY_ID, CapabilityId, CapabilityRegistry,
SystemPromptContext, collect_capabilities_with_configs,
};
use everruns_core::tools::ToolRegistry;
use everruns_core::typed_id::SessionId;
fn ctx() -> SystemPromptContext {
SystemPromptContext::without_file_store(SessionId::new())
}
fn cap(id: &str) -> AgentCapabilityConfig {
AgentCapabilityConfig {
capability_ref: CapabilityId::new(id),
config: serde_json::Value::Object(serde_json::Map::new()),
}
}
async fn assemble(
cap_ids: &[&str],
) -> (
ToolRegistry,
Vec<everruns_core::tool_types::ToolDefinition>,
Vec<String>,
) {
let registry = CapabilityRegistry::with_builtins();
let configs: Vec<AgentCapabilityConfig> = cap_ids.iter().map(|id| cap(id)).collect();
let collected = collect_capabilities_with_configs(&configs, ®istry, &ctx()).await;
let mut tool_registry = ToolRegistry::with_defaults();
for tool in collected.tools {
tool_registry.register_boxed(tool);
}
(
tool_registry,
collected.tool_definitions,
collected.applied_ids,
)
}
#[tokio::test]
async fn virtual_bash_session_auto_activates_spawn_background_in_lockstep() {
let (registry, defs, applied) = assemble(&["virtual_bash"]).await;
assert!(
registry.has("bash"),
"virtual_bash must contribute the bash tool to the executor"
);
assert!(
registry.has("spawn_background"),
"spawn_background must be in the worker executor registry when a \
background-capable tool is present (lockstep)"
);
let def_names: Vec<&str> = defs.iter().map(|d| d.name()).collect();
assert!(
def_names.contains(&"bash"),
"model-visible tool list must include bash; got: {:?}",
def_names
);
assert!(
def_names.contains(&"spawn_background"),
"model-visible tool list must include spawn_background when a \
background-capable tool is present; got: {:?}",
def_names
);
assert!(
applied
.iter()
.any(|id| id == BACKGROUND_EXECUTION_CAPABILITY_ID),
"background_execution must appear in applied_ids when auto-activated; \
got: {:?}",
applied
);
}
#[tokio::test]
async fn non_background_session_does_not_expose_spawn_background() {
let (registry, defs, applied) = assemble(&["current_time"]).await;
assert!(
!registry.has("spawn_background"),
"spawn_background must NOT be in the executor when no \
background-capable tool is collected (EVE-501 lockstep contract)"
);
let def_names: Vec<&str> = defs.iter().map(|d| d.name()).collect();
assert!(
!def_names.contains(&"spawn_background"),
"spawn_background must NOT be in tool_definitions without a \
background-capable tool; got: {:?}",
def_names
);
assert!(
!applied
.iter()
.any(|id| id == BACKGROUND_EXECUTION_CAPABILITY_ID),
"background_execution must NOT appear in applied_ids without a \
background-capable tool; got: {:?}",
applied
);
}
#[tokio::test]
async fn explicit_background_execution_plus_virtual_bash_is_idempotent() {
let (registry, defs, applied) =
assemble(&["virtual_bash", BACKGROUND_EXECUTION_CAPABILITY_ID]).await;
assert!(registry.has("spawn_background"));
let spawn_count = defs
.iter()
.filter(|d| d.name() == "spawn_background")
.count();
assert_eq!(
spawn_count, 1,
"spawn_background must appear exactly once in tool_definitions even \
under explicit + auto-activation overlap"
);
let applied_count = applied
.iter()
.filter(|id| id.as_str() == BACKGROUND_EXECUTION_CAPABILITY_ID)
.count();
assert_eq!(
applied_count, 1,
"background_execution must appear exactly once in applied_ids"
);
}
#[tokio::test]
async fn spawn_background_definition_carries_capability_attribution() {
let (_registry, defs, _applied) = assemble(&["virtual_bash"]).await;
let spawn_def = defs
.iter()
.find(|d| d.name() == "spawn_background")
.expect("spawn_background must be in tool_definitions");
let (cap_id, cap_name) = spawn_def
.capability_attribution()
.expect("spawn_background must carry capability attribution");
assert_eq!(cap_id, BACKGROUND_EXECUTION_CAPABILITY_ID);
assert_eq!(cap_name, Some("Background Execution"));
}