Files
DECNET/tests/realism/test_email_prompt.py
anti f2b3393669 chore: relicense to AGPL-3.0-or-later and add SPDX headers
Replaces LICENSE (GPLv3 -> AGPLv3) and prepends
`SPDX-License-Identifier: AGPL-3.0-or-later` to every source file
across decnet/, decnet_web/, tests/, scripts/, and tools/.

Rationale: closes the GPLv3 ASP loophole so any party operating a
modified DECNET as a network service must offer their modified
source. Personal copyright (Samuel Paschuan) + inbound=outbound
contributions make a future unilateral relicense infeasible.

- LICENSE: full AGPL-3.0 text (gnu.org/licenses/agpl-3.0.txt)
- COPYRIGHT: project copyright notice
- tools/add_spdx_headers.py: idempotent header injector
  (shebang- and PEP 263-aware)

Touches 1565 source files (.py, .ts, .tsx, .js, .jsx, .css, .sh).
No behavior change; comments only.
2026-05-22 21:04:16 -04:00

154 lines
4.5 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-or-later
"""Prompt builder behaviour: language constraint, em-dash suppression,
deterministic mannerism injection."""
from __future__ import annotations
import random
from decnet.realism.personas import EmailPersona
from decnet.realism.prompts.email import (
PromptInputs,
build,
select_mannerisms,
)
def _persona(**over) -> EmailPersona:
base = dict(
name="John Smith",
email="john@corp.com",
role="COO",
tone="formal",
mannerisms=[
"opens with 'I hope this finds you well'",
"uses 'Best regards' exclusively",
"references policy by number",
"ccs legal",
],
language="en",
)
base.update(over)
return EmailPersona(**base)
class _SeededRng:
"""Adapter so prompt code thinks it has a SystemRandom."""
def __init__(self, seed: int):
self._r = random.Random(seed)
def shuffle(self, seq):
self._r.shuffle(seq)
def random(self):
return self._r.random()
def choice(self, seq):
return self._r.choice(seq)
def test_select_mannerisms_returns_subset_of_pool():
persona = _persona()
picks = select_mannerisms(persona, rng=_SeededRng(0), n=2)
assert len(picks) == 2
assert all(m in persona.mannerisms for m in picks)
def test_select_mannerisms_deterministic_under_same_seed():
persona = _persona()
a = select_mannerisms(persona, rng=_SeededRng(42), n=2)
b = select_mannerisms(persona, rng=_SeededRng(42), n=2)
assert a == b
def test_select_mannerisms_returns_all_when_pool_smaller_than_n():
persona = _persona(mannerisms=["a"])
picks = select_mannerisms(persona, rng=_SeededRng(0), n=2)
assert picks == ["a"]
def test_select_mannerisms_empty_pool():
persona = _persona(mannerisms=[])
assert select_mannerisms(persona) == []
def test_build_includes_language_constraint_english():
sender = _persona(language="en")
recip = _persona(name="Sarah", email="sarah@corp.com", role="PM")
prompt, _ = build(
PromptInputs(sender=sender, recipient=recip, context_hint="budget"),
rng=_SeededRng(0),
)
assert "in English" in prompt
def test_build_includes_language_constraint_spanish():
sender = _persona(language="es")
recip = _persona(name="Sarah", email="sarah@corp.com", role="PM")
prompt, _ = build(
PromptInputs(sender=sender, recipient=recip, context_hint="budget"),
rng=_SeededRng(0),
)
assert "in Spanish" in prompt
def test_build_em_dash_suppression_default():
sender = _persona()
recip = _persona(name="Sarah", email="sarah@corp.com", role="PM")
prompt, _ = build(
PromptInputs(sender=sender, recipient=recip, context_hint="budget"),
rng=_SeededRng(0),
)
assert "Do NOT use em-dashes" in prompt
def test_build_em_dash_lifted_for_llm_heavy_persona():
sender = _persona(uses_llms_heavily=True)
recip = _persona(name="Sarah", email="sarah@corp.com", role="PM")
prompt, _ = build(
PromptInputs(sender=sender, recipient=recip, context_hint="budget"),
rng=_SeededRng(0),
)
assert "Do NOT use em-dashes" not in prompt
assert "fine" in prompt.lower()
def test_build_reply_thread_block_prefixes_re():
sender = _persona()
recip = _persona(name="Sarah", email="sarah@corp.com", role="PM")
prompt, _ = build(
PromptInputs(
sender=sender,
recipient=recip,
context_hint="budget",
parent_subject="Re: Q3 budget",
parent_excerpt="Numbers attached.",
),
rng=_SeededRng(0),
)
assert "REPLY in an ongoing thread" in prompt
assert "Re: Q3 budget" in prompt
assert "Numbers attached" in prompt
assert "prefixed with 'Re: '" in prompt
def test_build_returns_mannerisms_used_metadata():
sender = _persona()
recip = _persona(name="Sarah", email="sarah@corp.com", role="PM")
_, used = build(
PromptInputs(sender=sender, recipient=recip, context_hint="budget"),
rng=_SeededRng(7),
)
assert used
assert all(m in sender.mannerisms for m in used)
def test_build_uses_explicit_signature_when_provided():
sender = _persona(signature="-- John\\nCOO")
recip = _persona(name="Sarah", email="sarah@corp.com", role="PM")
prompt, _ = build(
PromptInputs(sender=sender, recipient=recip, context_hint="budget"),
rng=_SeededRng(0),
)
assert "Use this exact signature block" in prompt