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
3 changed files with 214 additions and 35 deletions

View file

@ -83,7 +83,7 @@ Manage agents across the swarm
* `mint-forge-token` — Check one agent's forge token, and mint it if it's missing or stale
* `set-state` — Declare the state a hive converges an agent to: `up`, `offline`, `paused` or `destroyed`
* `watch` — Follow an agent's terminal rows live: the newest retained rows, then each new one, one line per row, until Ctrl-C or the stream ends
* `inference` — Show the model, effort, subagent models and subagent cap the swarm sets for an agent, or change the model, effort and subagent models
* `inference` — Show the model, effort, subagent models, subagent cap and soft context limit the swarm sets for an agent, or change the model, effort and subagent models
* `permissions` — Show or change the permissions the swarm grants an agent
* `agents-md` — Show an agent's AGENTS.md, or edit it with a diff
@ -192,9 +192,9 @@ The swarm-level counterpart of `hivectl agent watch`, read from the swarm-contro
## `swarmctl agent inference`
Show the model, effort, subagent models and subagent cap the swarm sets for an agent, or change the model, effort and subagent models.
Show the model, effort, subagent models, subagent cap and soft context limit the swarm sets for an agent, or change the model, effort and subagent models.
`get` prints the subagent cap (`max_subagents`); `set` has no flag for it and keeps a stored one. Only swarm-ui sets it.
`get` prints the subagent cap (`max_subagents`) and the soft context limit (`soft_context_percent`); `set` has no flag for them and keeps stored ones. Only swarm-ui sets them.
A field the swarm sets wins over the agent's own value (its agent.nix or a `hyperhive-model`/`hyperhive-effort` file) from its next turn on; the agent reads its settings every ten seconds. A field the swarm doesn't set, or clears, leaves the agent on its own value.

View file

@ -1,8 +1,8 @@
# Per-agent inference settings
The swarm can set the model and reasoning effort each agent's turns run on,
plus the models it may start subagents on and how many subagents it may run
at once. A field you set wins over the
plus the models it may start subagents on, how many subagents it may run
at once, and a soft limit on how full its context may get before it compacts. A field you set wins over the
agent's own value; a field you leave unset keeps the agent on its own value,
so an agent you set nothing for runs as it does today.
@ -25,6 +25,14 @@ swarmctl agent inference clear iris
dialog; `set` has no flag for it and keeps the stored one. It's a whole
number from 0 to 32, where 0 allows no subagents; unset means no cap
([`subagent.md`](../agent-tools/subagent.md#how-many-subagents-may-run-at-once)).
- You set the soft context limit, `soft_context_percent`, in the same
dialog; `set` has no flag for it either. It is the percent of the model's
context window at which the agent compacts at the end of a turn, in place of
the harness's own 75%: 20 on a 1M window compacts once the context passes
200k. A turn can still run past it, and it changes nothing else (the idle
auto-reset, the context shown in the UI). It's a whole number from 5 to 100;
unset keeps the harness's own watermark
([`claude-invocation.md`](../turn-loop/claude-invocation.md)).
- `get` shows each field, naming the unset ones (or says the swarm sets
nothing for the agent), and then the model and effort the agent reports
running on, each with where it comes from.
@ -45,6 +53,7 @@ model: opus
effort: (not set; the agent's own)
subagent_models: (not set; the agent's own)
max_subagents: (not set; no cap)
soft_context_percent: (not set; the harness's own watermark)
running model: opus (swarm)
running effort: medium (local_file)
```
@ -93,7 +102,8 @@ which swarm-controller alone writes:
"model": "opus",
"effort": "high",
"subagent_models": ["haiku", "sonnet"],
"max_subagents": 3
"max_subagents": 3,
"soft_context_percent": 20
}
```
@ -106,7 +116,7 @@ warning in its log, until the next `PUT` replaces it.
| method | path | body |
| -------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `GET` | `/api/agents/<agent>/inference` | —; answers `{"configured": <the stored value, or null>, "effective": <what the agent reported, or null>}` |
| `PUT` | `/api/agents/<agent>/inference` | the whole value, replacing the stored one; the controller refuses unknown fields, an unknown effort, or a model name with whitespace or a leading `-`, or a `max_subagents` above 32 |
| `PUT` | `/api/agents/<agent>/inference` | the whole value, replacing the stored one; the controller refuses unknown fields, an unknown effort, or a model name with whitespace or a leading `-`, a `max_subagents` above 32, or a `soft_context_percent` outside 5 to 100 |
| `DELETE` | `/api/agents/<agent>/inference` | —; answers 204 |
An agent's own queue credential grants it
@ -118,6 +128,10 @@ The harness (`hive-agent`'s `swarm_inference`) applies a set field to the
in-memory model or effort without writing `hyperhive-model` or
`hyperhive-effort`, which keep the agent's own value.
The same loop hands `soft_context_percent` to the Bus
(`set_soft_context_percent`), which the compaction policy reads when it decides
at turn end; a key with no limit, or no key, clears it on the next read.
The subagent daemon (`hive-subagent-mcp`'s `swarm_models`) reads
`subagent_models` and `max_subagents` with the same direct get, under the
same credential, on each `start` or `continue`.

View file

@ -164,7 +164,10 @@ The **when** for hyperhive's own policy is a `hive_claude::CompactionPolicy` inj
`turn::make_session` builds a `PercentPolicy` that compacts once the
model-reported context fill reaches `HIVE_COMPACT_WATERMARK_PERCENT`
(default **75%**), falling back to `harness_state::context_window_tokens(model)`
for the window on turns the model didn't report one. `0` disables proactive
for the window on turns the model didn't report one. The swarm can replace
that percent per agent with its `soft_context_percent`
([`inference.md`](../swarm/inference.md)); `turn::SoftLimitPolicy` reads it
for each decision. `0` disables proactive
compaction (the reactive path always applies). The proactive path is
best-effort — a failed checkpoint or `/compact` never fails the turn that
already succeeded. An ACP agent gets the same policy; how it compacts is in