hive-sh4re + docs: extract HelperEvent prose (#717 batch 7)
This commit is contained in:
parent
d59bfb899f
commit
f3fefe7f7e
2 changed files with 29 additions and 61 deletions
|
|
@ -497,6 +497,17 @@ regular claude turn so the manager can react. Variants
|
||||||
The recipient responds via `Answer { id, answer }` and the
|
The recipient responds via `Answer { id, answer }` and the
|
||||||
asker sees the matching `QuestionAnswered`.
|
asker sees the matching `QuestionAnswered`.
|
||||||
|
|
||||||
|
Optional `sha` / `tag` fields on `ApprovalResolved`, `Spawned`, and
|
||||||
|
`Rebuilt` carry the canonical hive-c0re-vouched commit sha plus the
|
||||||
|
applied-repo's terminal tag (`deployed/<id>` / `failed/<id>` /
|
||||||
|
`denied/<id>` for approval-driven flows; `approved/<id>` for the
|
||||||
|
rare bare-approval case where no underlying action runs). Both are
|
||||||
|
`Option`: `None` on the paths that don't change the deployed commit
|
||||||
|
(e.g. `auto_update::rebuild_agent` reapplying the existing main, or
|
||||||
|
the dashboard `↻ R3BU1LD` button when the lock didn't move). When
|
||||||
|
set, `git show <sha>` against `/agents/<n>/applied.git` inside the
|
||||||
|
manager container yields the exact tree that was referenced.
|
||||||
|
|
||||||
To add a new event: new `HelperEvent` variant + call sites + update
|
To add a new event: new `HelperEvent` variant + call sites + update
|
||||||
`prompts/system.md` (`<!-- role:manager -->` block, the lifecycle-
|
`prompts/system.md` (`<!-- role:manager -->` block, the lifecycle-
|
||||||
event list) so the manager knows the new shape.
|
event list) so the manager knows the new shape.
|
||||||
|
|
|
||||||
|
|
@ -519,11 +519,12 @@ pub const SYSTEM_SENDER: &str = "system";
|
||||||
|
|
||||||
/// Out-of-band events the host-side daemon pushes to the manager's inbox.
|
/// Out-of-band events the host-side daemon pushes to the manager's inbox.
|
||||||
/// Serialised as JSON in `Message::body` (sender = `SYSTEM_SENDER`).
|
/// Serialised as JSON in `Message::body` (sender = `SYSTEM_SENDER`).
|
||||||
|
/// Per-variant triggers + the optional `sha`/`tag` semantics live in
|
||||||
|
/// `docs/approvals.md::Helper events to the manager`.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(tag = "event", rename_all = "snake_case")]
|
#[serde(tag = "event", rename_all = "snake_case")]
|
||||||
pub enum HelperEvent {
|
pub enum HelperEvent {
|
||||||
/// An approval was approved/denied/failed; if approved, the underlying
|
/// An approval transitioned to a terminal state.
|
||||||
/// action (rebuild or spawn) has already run by the time this lands.
|
|
||||||
ApprovalResolved {
|
ApprovalResolved {
|
||||||
id: i64,
|
id: i64,
|
||||||
agent: String,
|
agent: String,
|
||||||
|
|
@ -531,105 +532,61 @@ pub enum HelperEvent {
|
||||||
status: ApprovalStatus,
|
status: ApprovalStatus,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
note: Option<String>,
|
note: Option<String>,
|
||||||
/// Canonical sha hive-c0re fetched into applied at submission
|
|
||||||
/// time. `git show <sha>` against `/agents/<n>/applied.git`
|
|
||||||
/// inside the manager container yields the exact tree being
|
|
||||||
/// referenced.
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
sha: Option<String>,
|
sha: Option<String>,
|
||||||
/// Terminal tag name in the applied repo for this approval —
|
|
||||||
/// `deployed/<id>`, `failed/<id>`, or `denied/<id>` (and
|
|
||||||
/// `approved/<id>` for the rare bare-approval case where
|
|
||||||
/// no underlying action runs).
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
tag: Option<String>,
|
tag: Option<String>,
|
||||||
},
|
},
|
||||||
/// A new container was spawned (post-approval or via the admin CLI
|
/// A new container was spawned. `ok = false` = spawn failed.
|
||||||
/// bypass path). `ok=false` means the spawn failed.
|
|
||||||
Spawned {
|
Spawned {
|
||||||
agent: String,
|
agent: String,
|
||||||
ok: bool,
|
ok: bool,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
note: Option<String>,
|
note: Option<String>,
|
||||||
/// Sha of the `deployed/0` commit seeded by hive-c0re on
|
|
||||||
/// first spawn (Some on success, None on failure).
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
sha: Option<String>,
|
sha: Option<String>,
|
||||||
},
|
},
|
||||||
/// A container was rebuilt (auto-update on flake rev change, or a
|
/// A container was rebuilt (auto-update or manual).
|
||||||
/// manual rebuild from CLI/dashboard).
|
|
||||||
Rebuilt {
|
Rebuilt {
|
||||||
agent: String,
|
agent: String,
|
||||||
ok: bool,
|
ok: bool,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
note: Option<String>,
|
note: Option<String>,
|
||||||
/// Sha that ended up at `deployed/<id>` on success, or the
|
|
||||||
/// proposal sha that just got tagged `failed/<id>` on
|
|
||||||
/// failure. None for the (rare) rebuild path that doesn't go
|
|
||||||
/// through an approval (e.g. `auto_update::rebuild_agent`
|
|
||||||
/// reapplying the existing main).
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
sha: Option<String>,
|
sha: Option<String>,
|
||||||
/// `deployed/<id>` or `failed/<id>` for approval-driven
|
|
||||||
/// rebuilds; None for auto-update / dashboard rebuilds that
|
|
||||||
/// don't change the deployed commit.
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
tag: Option<String>,
|
tag: Option<String>,
|
||||||
},
|
},
|
||||||
/// A new agent's proposed config repo was initialised (post-`InitConfig`
|
/// A new agent's proposed config repo was seeded post-`InitConfig`.
|
||||||
/// approval). The manager can now edit `/agents/<agent>/config/agent.nix`,
|
|
||||||
/// commit the changes, and submit a `RequestApplyCommit` — which will
|
|
||||||
/// create the container on first deploy, then rebuild on every subsequent
|
|
||||||
/// deploy.
|
|
||||||
ConfigReady { agent: String },
|
ConfigReady { agent: String },
|
||||||
/// A sub-agent's container was stopped (the systemd unit is down;
|
/// A sub-agent's container was stopped (systemd unit down; state kept).
|
||||||
/// persistent state is unchanged).
|
|
||||||
Killed { agent: String },
|
Killed { agent: String },
|
||||||
/// A sub-agent's container was torn down (container removed; state
|
/// A sub-agent's container was torn down (state dirs preserved by default).
|
||||||
/// dirs preserved per `destroy` semantics).
|
|
||||||
Destroyed { agent: String },
|
Destroyed { agent: String },
|
||||||
/// A sub-agent's container has no claude session yet (first
|
/// A sub-agent's container has no claude session yet.
|
||||||
/// spawn, or `--purge` wiped creds). Manager can't do anything
|
|
||||||
/// about it directly — login is interactive OAuth — but it
|
|
||||||
/// surfaces so the manager knows the agent is in partial-run
|
|
||||||
/// mode and can flag the operator.
|
|
||||||
NeedsLogin { agent: String },
|
NeedsLogin { agent: String },
|
||||||
/// An agent successfully completed claude login — the session
|
/// A sub-agent just completed claude login.
|
||||||
/// dir now contains creds. Transition fires once per login.
|
|
||||||
LoggedIn { agent: String },
|
LoggedIn { agent: String },
|
||||||
/// An agent's recorded flake rev is stale relative to the
|
/// A sub-agent's recorded flake rev is stale relative to hyperhive.
|
||||||
/// current hyperhive rev. The manager has the `update` tool to
|
|
||||||
/// trigger a rebuild without operator approval (it's a no-op
|
|
||||||
/// when nothing actually changed).
|
|
||||||
NeedsUpdate { agent: String },
|
NeedsUpdate { agent: String },
|
||||||
/// Container exited without an operator-initiated stop. Fired by
|
/// Container exited without an operator-initiated stop (crash).
|
||||||
/// the crash watcher when an agent's container transitions from
|
|
||||||
/// running → stopped and no `Stopping` / `Restarting` /
|
|
||||||
/// `Destroying` transient was set, so the operator (or the
|
|
||||||
/// manager) knows it crashed rather than was killed on purpose.
|
|
||||||
ContainerCrash {
|
ContainerCrash {
|
||||||
agent: String,
|
agent: String,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
note: Option<String>,
|
note: Option<String>,
|
||||||
},
|
},
|
||||||
/// A question queued via `Ask` was answered (by the operator via
|
/// A question queued via `Ask` was answered. `id` matches the
|
||||||
/// the dashboard, or by another agent via `Answer`). `id` matches
|
/// originating `QuestionQueued.id`; `answerer` is `"operator"` /
|
||||||
/// the `QuestionQueued.id` returned to the asker; `question`
|
/// a peer agent name / `"ttl-watchdog"` on expiry.
|
||||||
/// echoes the original prompt so the asker can stitch the answer
|
|
||||||
/// back to context across compactions; `answerer` is who answered
|
|
||||||
/// (`"operator"` or a peer agent name).
|
|
||||||
QuestionAnswered {
|
QuestionAnswered {
|
||||||
id: i64,
|
id: i64,
|
||||||
question: String,
|
question: String,
|
||||||
answer: String,
|
answer: String,
|
||||||
answerer: String,
|
answerer: String,
|
||||||
},
|
},
|
||||||
/// A peer (or the manager) asked this agent a question via
|
/// A peer (or the manager) asked this agent a question. Recipient
|
||||||
/// `Ask { to: Some(<this-agent>), ... }`. The recipient should
|
/// replies via `Answer { id, answer }`; the answer routes back to
|
||||||
/// answer via `Answer { id, answer }` on their socket; the answer
|
/// the asker as `QuestionAnswered`.
|
||||||
/// will route back to the asker as a `QuestionAnswered` event.
|
|
||||||
/// `options` + `multi` mirror the original `Ask` args so the
|
|
||||||
/// answerer knows what shape of reply is expected.
|
|
||||||
QuestionAsked {
|
QuestionAsked {
|
||||||
id: i64,
|
id: i64,
|
||||||
asker: String,
|
asker: String,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue