From f490e0750930797d0a969a659f2d71e1e8d5c83b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?m=C3=BCde?= Date: Sun, 5 Jul 2026 22:36:10 +0200 Subject: [PATCH] refactor(prompt): drop unreachable role-block defensive branches; keep marker grammar --- docs/turn-loop.md | 16 +++++----- hive-ag3nt/src/prompt.rs | 68 ++++++---------------------------------- 2 files changed, 17 insertions(+), 67 deletions(-) diff --git a/docs/turn-loop.md b/docs/turn-loop.md index 3e9d75f0..70aee411 100644 --- a/docs/turn-loop.md +++ b/docs/turn-loop.md @@ -350,14 +350,14 @@ socket at `/run/hive/` once at startup: favour of this direct injection). Passed via `--system-prompt-file`. - **Marker grammar.** `` opens a block; matching - `` closes it. The renderer always uses role `agent`. - Blocks with other role tags are elided. Nesting is NOT supported — - a stray opener overrides until its closing tag (or end of file). A - mismatched closer is elided from the output but does NOT pop the - active role. Whitespace inside markers is tolerated - (`` parses the same as ``). - Content outside any marker is always included. + **Marker grammar.** `` opens a block; any + `` closes the current block. The renderer always uses + role `agent`, so blocks with other role tags are elided. Nesting is NOT + supported — a stray opener with no closer runs until end of file. + Whitespace inside markers is tolerated (`` parses the + same as ``). Content outside any marker is always + included. Today's `system.md` carries no markers (single agent role) — + the grammar stays wired for a future manager / multi-role prompt. **`hive_identity` / `swarm_identity` shape.** Each carries a leading space + backticked name (` on hive \`pr1ma\``, diff --git a/hive-ag3nt/src/prompt.rs b/hive-ag3nt/src/prompt.rs index aa584747..5c2e8e01 100644 --- a/hive-ag3nt/src/prompt.rs +++ b/hive-ag3nt/src/prompt.rs @@ -55,14 +55,12 @@ pub fn render( } } -/// Walk `template` line-by-line. Inside a `` block, -/// suppress all lines unless `X == target`. Marker lines themselves are -/// always elided from the output. Unbalanced openers (no matching -/// closer) hold the suppression state until end-of-file. A mismatched -/// closer (`` inside a `role:agent` block) is -/// elided from the output but does NOT reset the active role — keeps -/// the suppression conservative so a typo can't dump wrong-flavor -/// content. +/// Walk `template` line-by-line, stripping `` / +/// `` marker lines and suppressing the lines inside a block +/// unless `X == target`. A close marker ends the current block. Production +/// `system.md` carries no markers today (single agent role — see the module +/// doc), so this is effectively a passthrough; the marker grammar stays wired +/// for a future manager / multi-role prompt. fn filter_role_blocks(template: &str, target: &str) -> String { let mut out = String::with_capacity(template.len()); // None = outside any block; Some(role) = inside role-tagged block. @@ -73,19 +71,11 @@ fn filter_role_blocks(template: &str, target: &str) -> String { active_role = Some(role); continue; } - if let Some(close_role) = parse_close_marker(trimmed) { - if active_role == Some(close_role) { - active_role = None; - } - // Mismatched close: elide the marker line but keep the - // active role intact so wrong-flavor content stays gated. + if parse_close_marker(trimmed).is_some() { + active_role = None; continue; } - let include = match active_role { - None => true, - Some(role) => role == target, - }; - if include { + if active_role.is_none_or(|role| role == target) { out.push_str(line); out.push('\n'); } @@ -245,46 +235,6 @@ shared closer assert_eq!(parse_close_marker("just text"), None); } - #[test] - fn mismatched_close_keeps_active_role() { - // `` block with a stray `` - // closer inside: the manager-tagged close must NOT pop the agent - // gate, else manager-target output would leak the agent block's - // text (or vice-versa). Stray marker line itself is still elided. - let template = "shared\n\ - \n\ - agent line 1\n\ - \n\ - agent line 2\n\ - \n\ - shared end\n"; - let manager = filter_role_blocks(template, "manager"); - // Both agent lines stay gated out for the manager target; the - // stray close didn't accidentally pop the role. Stray marker - // itself elided from the output. - assert!(!manager.contains("agent line 1")); - assert!(!manager.contains("agent line 2")); - assert!(!manager.contains("\nm-only\nstill m-only\n"; - let agent = filter_role_blocks(template, "agent"); - assert_eq!(agent, "shared\n"); - } - #[test] fn render_substitutes_label_and_pronouns() { // Real template's first agent line — keeps the renderer