35 lines
1.1 KiB
Python
35 lines
1.1 KiB
Python
"""System prompt assembly from a list of source files.
|
|
|
|
The gateway holds no prompt text: an agent names its granules (paths from
|
|
``config.py``) and :func:`assemble` concatenates them in that order, so the
|
|
result is byte-for-byte identical for every session of the same agent as
|
|
long as the files are. Each granule's hash is logged at assembly so a
|
|
drifted prompt can be traced to the file that changed.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import logging
|
|
from pathlib import Path
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Iterable
|
|
|
|
__all__ = ["assemble"]
|
|
|
|
_log = logging.getLogger("beaver_gateway.core.prompt")
|
|
|
|
|
|
def assemble(sources: Iterable[str | Path]) -> str:
|
|
parts: list[str] = []
|
|
for source in sources:
|
|
path = Path(source)
|
|
text = path.read_text(encoding="utf-8").strip()
|
|
digest = hashlib.sha256(text.encode("utf-8")).hexdigest()[:12]
|
|
_log.info("prompt granule %s sha=%s bytes=%d", path, digest, len(text))
|
|
if text:
|
|
parts.append(text)
|
|
return "\n\n".join(parts) + "\n"
|