A `start` may now name a role: `role: "reviewer"` loads the spawning agent's own `subagent_roles/reviewer.md` and renders it, alone, into one per-session file that `--append-system-prompt-file` points at. The role is the system prompt; the task is the turn, never the other way round — a task baked into the system prompt would re-assert itself as an instruction on every later turn of a continued session, not just the one it was written for. The task instructions (`prompt_file`) are read and folded ahead of the turn's own prompt instead, the same channel that carries them to the subagent without a role. The argument is optional, so every existing call is unchanged — pinned by a test that a pre-role payload still deserializes with `role` absent from the schema's required set, and another that the no-role path reaches claude with the caller's own file, unrendered, and the trigger untouched. With a role, one test pins the system-prompt file to the role's text and nothing of the task, and another pins the task still reaching the subagent as the turn's prompt. A role name with no file fails the call, before the session name is even reserved, and the error lists the roles the directory does hold. No agent ships roles yet, so named-but-missing is the ordinary first-run state; a fallback there would spawn a subagent under a prompt missing every clause the role existed to carry. An empty file and a name that is not a plain identifier refuse the same way.
52 lines
2.2 KiB
Rust
52 lines
2.2 KiB
Rust
//! The per-agent paths this daemon needs.
|
|
|
|
use std::path::PathBuf;
|
|
|
|
/// The harness-served in-agent todo socket (loose-ends v2). This daemon
|
|
/// pushes exactly one todo per subagent lifetime — the completion summary,
|
|
/// once its background turn finishes. Override via `HIVE_AGENT_SOCKET`;
|
|
/// same resolution as `hive-bash-mcp`'s own `paths::agent_socket`.
|
|
#[must_use]
|
|
pub fn agent_socket() -> PathBuf {
|
|
std::env::var_os("HIVE_AGENT_SOCKET").map_or_else(
|
|
|| PathBuf::from(hive_agent_sock::DEFAULT_AGENT_SOCKET),
|
|
PathBuf::from,
|
|
)
|
|
}
|
|
|
|
/// Durable state directory for the current agent. Same resolution as
|
|
/// `hive-agent`'s own `paths::state_dir` — reads `HYPERHIVE_STATE_DIR`
|
|
/// (always injected via `systemd.globalEnvironment` by the meta flake),
|
|
/// falling back to the `HIVE_LABEL`-derived pattern for dev/test
|
|
/// environments where the env var may not be set. Copied rather than shared
|
|
/// with `hive-agent` (a binary crate with no lib target) — a five-line env
|
|
/// read isn't worth a crate dependency to dedupe.
|
|
#[must_use]
|
|
pub fn state_dir() -> PathBuf {
|
|
if let Some(p) = std::env::var_os("HYPERHIVE_STATE_DIR") {
|
|
return PathBuf::from(p);
|
|
}
|
|
let label = std::env::var("HIVE_LABEL").unwrap_or_default();
|
|
PathBuf::from(format!("/agents/{label}/state"))
|
|
}
|
|
|
|
/// Where this agent's named subagent role files live, one markdown file per
|
|
/// role under the agent's own [`state_dir`]. Per-agent rather than
|
|
/// hive-wide: the clauses a role carries came out of one agent's own prompt
|
|
/// files, and this daemon only ever spawns on behalf of that agent. The
|
|
/// directory is a convention, not a registry — it is created by whoever
|
|
/// writes a role into it, and its absence simply means this agent ships no
|
|
/// roles yet (see `crate::role`).
|
|
#[must_use]
|
|
pub fn subagent_roles_dir() -> PathBuf {
|
|
state_dir().join("subagent_roles")
|
|
}
|
|
|
|
/// Harness-internal scratch dir this daemon writes its own generated
|
|
/// subagent `--mcp-config` file into (see `crate::mcp_config`). Delegates to
|
|
/// the shared resolver so this and `hive-agent`'s own harness dir always
|
|
/// agree on the same path.
|
|
#[must_use]
|
|
pub fn harness_dir() -> PathBuf {
|
|
hive_agent_sock::paths::harness_dir()
|
|
}
|