diff --git a/session_bot/render.py b/session_bot/render.py
index b357b76..ba11e1c 100644
--- a/session_bot/render.py
+++ b/session_bot/render.py
@@ -43,6 +43,20 @@ def build_actor_line(actor: dict, state: dict, config: dict) -> str:
return line
+def build_actor_fragment(actor: dict, state: dict, config: dict) -> str:
+ actor_state = state.get("actors", {})
+ status_labels = {**DEFAULT_STATUS_LABELS, **config.get("status_labels", {})}
+ current = actor_state.get(actor["key"], {})
+ status = current.get("status", actor.get("default_status", "backstage"))
+ phrase = current.get("phrase", actor.get("phrases", {}).get(status, ""))
+ label = status_labels.get(status, status)
+
+ fragment = f"{escape(label)}."
+ if phrase:
+ fragment = f"{fragment}\n {escape(phrase)}"
+ return fragment
+
+
def build_actor_lines(config: dict, state: dict, skip_keys: set[str] | None = None) -> str:
actor_lines: list[str] = []
skip_keys = skip_keys or set()
@@ -66,7 +80,17 @@ def replace_actor_placeholders(template: str, config: dict, state: dict) -> tupl
if actor is None:
return match.group(0)
used_keys.add(actor["key"])
- return build_actor_line(actor, state, config)
+
+ line_start = template.rfind("\n", 0, match.start()) + 1
+ line_end = template.find("\n", match.end())
+ if line_end == -1:
+ line_end = len(template)
+ line_text = template[line_start:line_end]
+
+ if line_text.strip().lower() == match.group(0).strip().lower():
+ return build_actor_line(actor, state, config)
+
+ return build_actor_fragment(actor, state, config)
return ACTOR_PLACEHOLDER_RE.sub(repl, template), used_keys
diff --git a/tests/test_render.py b/tests/test_render.py
index 57694bf..3dafba1 100644
--- a/tests/test_render.py
+++ b/tests/test_render.py
@@ -64,3 +64,32 @@ def test_build_channel_text_supports_per_actor_placeholders() -> None:
assert text.count("ASTAT") == 1
assert text.count("MARI") == 1
+
+
+def test_build_channel_text_inlines_actor_fragment_without_duplication() -> None:
+ config = {
+ "template_text": (
+ '🌟 LIEBE she/her {{actor:liebe}}\n'
+ '🌟 VICTOR tech bot'
+ ),
+ "actors": [
+ {
+ "key": "liebe",
+ "display_name": "LIEBE",
+ "display_html": "LIEBE",
+ "link": "https://t.me/liebe",
+ "pronouns": "she/her",
+ "meta_html": " she/her ",
+ "emoji": "🌟",
+ "default_status": "backstage",
+ "phrases": {"backstage": "в закулисье."},
+ }
+ ],
+ }
+ state = {"actors": {}}
+
+ text = build_channel_text(config, state)
+
+ assert text.count("LIEBE") == 1
+ assert "she/her в закулисье." in text
+ assert "в закулисье." in text