Watch
0
0
Fork
You've already forked hyperhive
0

swarm: a soft context limit per agent, as a percent of the window, applied at turn end

This commit is contained in:
damocles 2026-11-15 15:13:50 +01:00 • committed by mara
commit 1e03979836

View file

@ -1,5 +1,5 @@
//! `/api/agents/{name}/inference` — the model, effort, subagent models and
//! subagent cap the swarm sets for one agent, and what the agent reports
//! `/api/agents/{name}/inference` — the model, effort, subagent models,
//! subagent cap and soft context limit the swarm sets for one agent, and what the agent reports
//! running on.
//!
//! Each agent's settings are one value under its own key of `agent-inference`
@ -28,7 +28,8 @@ use axum::http::StatusCode;
use futures_util::StreamExt as _;
use problem_details::ProblemDetails;
use swarm_controller_api::inference::{
AgentInferenceView, EffectiveInference, InferenceSettings, MAX_SUBAGENTS,
AgentInferenceView, EffectiveInference, InferenceSettings, MAX_SOFT_CONTEXT_PERCENT,
MAX_SUBAGENTS, MIN_SOFT_CONTEXT_PERCENT,
};
use swarm_queue_client::agent_inference;
use swarm_wire::agent_inference::{AgentInference, Effective};
@ -47,6 +48,7 @@ fn settings_view(v: AgentInference) -> InferenceSettings {
effort: v.effort,
subagent_models: v.subagent_models,
max_subagents: v.max_subagents,
soft_context_percent: v.soft_context_percent,
}
}
@ -91,11 +93,19 @@ pub(crate) fn into_stored(settings: InferenceSettings) -> Result<AgentInference,
"max_subagents is {max}; it is from 0 (no subagents) to {MAX_SUBAGENTS}, or left out for no cap"
));
}
if let Some(percent) = settings.soft_context_percent
&& !(MIN_SOFT_CONTEXT_PERCENT..=MAX_SOFT_CONTEXT_PERCENT).contains(&percent)
{
return Err(format!(
"soft_context_percent is {percent}; it is from {MIN_SOFT_CONTEXT_PERCENT} to {MAX_SOFT_CONTEXT_PERCENT}, or left out for the harness's own watermark"
));
}
Ok(AgentInference {
model: settings.model,
effort: settings.effort,
subagent_models: settings.subagent_models,
max_subagents: settings.max_subagents,
soft_context_percent: settings.soft_context_percent,
})
}
@ -251,7 +261,8 @@ pub(crate) async fn get_agent_inference(
ones whole", body = InferenceSettings),
(status = 400, description = "not an identifier, not declared on any hive, or a \
model name is empty, has whitespace, starts with `-`, or is listed \
twice, or `max_subagents` is above 32 (problem+json)",
twice, or `max_subagents` is above 32, or `soft_context_percent` is outside \
its range (problem+json)",
body = String),
(status = 422, description = "an unknown field, or an effort that is not one of \
the five levels"),
@ -394,6 +405,7 @@ mod tests {
effort: Some(Effort::High),
subagent_models: Some(vec!["haiku".to_owned()]),
max_subagents: None,
soft_context_percent: None,
}
);
assert_eq!(
@ -555,6 +567,25 @@ mod tests {
assert!(settings(r#"{"max_subagents":-1}"#).is_err());
}
#[test]
fn soft_context_percent_outside_its_range_is_refused() {
for percent in [0, MIN_SOFT_CONTEXT_PERCENT - 1, MAX_SOFT_CONTEXT_PERCENT + 1] {
let json = format!(r#"{{"soft_context_percent":{percent}}}"#);
assert!(into_stored(settings(&json).unwrap()).is_err(), "{json}");
}
assert!(settings(r#"{"soft_context_percent":-1}"#).is_err());
assert!(settings(r#"{"soft_context_percent":256}"#).is_err());
}
#[test]
fn soft_context_percent_in_range_is_stored() {
for percent in [MIN_SOFT_CONTEXT_PERCENT, 20, MAX_SOFT_CONTEXT_PERCENT] {
let json = format!(r#"{{"soft_context_percent":{percent}}}"#);
let stored = into_stored(settings(&json).unwrap()).unwrap();
assert_eq!(stored.soft_context_percent, Some(percent));
}
}
#[test]
fn max_subagents_in_range_is_stored() {
for max in [0, 1, 3, MAX_SUBAGENTS] {