archetypes: prefill the create form from flake-declared agent archetypes
A flake declares agent archetypes in its `hyperhiveArchetypes` output,
`<name> = { module; meta; }`. The hyperhive flake ships `reviewer`
(default permissions without `execution`).
swarm-builder answers `$SWARM.builder.archetypes` with the `meta` of
every archetype its own hyperhive source declares. swarm-controller asks
once the queue connects and every 10 minutes, checks each archetype as
`POST /api/agents` checks its settings, and stores the result in the
`agent-archetypes` KV bucket when it changed. `GET /api/archetypes`
serves it, and the create form's archetype select prefills permissions,
resource caps and inference from it.
The agent created is an ordinary agent with its own config repo; the
archetype's module is not applied yet.
Refs #5386
This commit is contained in:
parent
eb92e83c95
commit
51035eac1d
22 changed files with 1244 additions and 30 deletions
|
|
@ -263,14 +263,16 @@ impl Policy {
|
|||
}
|
||||
}
|
||||
|
||||
/// What the builder may do: hear build requests and answer each on its
|
||||
/// reply subject, for as long as a build may take. Its publish list is
|
||||
/// its own inbox, for [`Self::review_classifier_permissions`]' reason.
|
||||
/// What the builder may do: hear build and archetype evaluation requests
|
||||
/// and answer each on its reply subject, for as long as a build may take.
|
||||
/// Its publish list is its own inbox, for
|
||||
/// [`Self::review_classifier_permissions`]' reason.
|
||||
fn builder_permissions(client_id: &str) -> Permissions {
|
||||
Permissions {
|
||||
publish: vec![Self::inbox(client_id)],
|
||||
subscribe: Some(vec![
|
||||
swarm_queue_client::builder::SUBJECT.to_owned(),
|
||||
swarm_queue_client::builder::ARCHETYPES_SUBJECT.to_owned(),
|
||||
Self::inbox(client_id),
|
||||
]),
|
||||
responses: Some(swarm_queue_client::builder::REPLY_DEADLINE),
|
||||
|
|
@ -643,6 +645,8 @@ impl Policy {
|
|||
swarm_queue_client::review_classifier::SUBJECT.to_owned(),
|
||||
// A build of an agent config, sent as a request the same way.
|
||||
swarm_queue_client::builder::SUBJECT.to_owned(),
|
||||
// An archetype evaluation, sent as a request the same way.
|
||||
swarm_queue_client::builder::ARCHETYPES_SUBJECT.to_owned(),
|
||||
// An operator's claude login step, sent as a request the same way.
|
||||
swarm_queue_client::claude_login::SUBJECT.to_owned(),
|
||||
// The wanted-state buckets — one per hive, all created and written
|
||||
|
|
@ -1463,7 +1467,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn the_builder_hears_its_subject_and_inbox_only_and_answers_by_reply() {
|
||||
use swarm_queue_client::builder::{REPLY_DEADLINE, SUBJECT};
|
||||
use swarm_queue_client::builder::{ARCHETYPES_SUBJECT, REPLY_DEADLINE, SUBJECT};
|
||||
use swarm_queue_client::client_inbox_prefix;
|
||||
|
||||
let p = policy()
|
||||
|
|
@ -1472,6 +1476,7 @@ mod tests {
|
|||
.expect("a configured builder is admitted");
|
||||
let inbox = client_inbox_prefix(BUILDER);
|
||||
assert!(may_subscribe(&p, SUBJECT));
|
||||
assert!(may_subscribe(&p, ARCHETYPES_SUBJECT));
|
||||
assert!(may_subscribe(&p, &reply(&inbox)));
|
||||
for refused in [
|
||||
">".to_owned(),
|
||||
|
|
@ -1492,24 +1497,26 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn only_the_reader_may_send_a_build() {
|
||||
use swarm_queue_client::builder::SUBJECT;
|
||||
use swarm_queue_client::builder::{ARCHETYPES_SUBJECT, SUBJECT};
|
||||
|
||||
let p = with_classifier().with_builders(vec![BUILDER.to_owned()]);
|
||||
let reader = p.permissions("swarm-controller").expect("the reader");
|
||||
assert!(reader.publish.iter().any(|g| covers(g, SUBJECT)));
|
||||
for (who, grant) in [
|
||||
("a hive", p.permissions("hive-alpha").expect("a hive")),
|
||||
("the builder", p.permissions(BUILDER).expect("admitted")),
|
||||
(
|
||||
"the classifier",
|
||||
p.permissions(CLASSIFIER).expect("admitted"),
|
||||
),
|
||||
] {
|
||||
assert!(
|
||||
!grant.publish.iter().any(|g| covers(g, SUBJECT)),
|
||||
"{who} may send a build: {:?}",
|
||||
grant.publish
|
||||
);
|
||||
for subject in [SUBJECT, ARCHETYPES_SUBJECT] {
|
||||
assert!(reader.publish.iter().any(|g| covers(g, subject)));
|
||||
for (who, grant) in [
|
||||
("a hive", p.permissions("hive-alpha").expect("a hive")),
|
||||
("the builder", p.permissions(BUILDER).expect("admitted")),
|
||||
(
|
||||
"the classifier",
|
||||
p.permissions(CLASSIFIER).expect("admitted"),
|
||||
),
|
||||
] {
|
||||
assert!(
|
||||
!grant.publish.iter().any(|g| covers(g, subject)),
|
||||
"{who} may send to {subject}: {:?}",
|
||||
grant.publish
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue