Skip to content

symfonic.capabilities.prompting.hms_state

hms_state

The {{VARIABLE}} values the HMS system template renders from.

A pure function of explicit values. It reads no agent, config, registry or scope: the caller resolves the tenant, the tool names and the domain description (whose truncation policy lives with the config that owns the cap) and passes them in. That is what lets a legacy engine and a future Agent composition build byte-identical state without either importing the other.

Memory slots are present but deliberately not filled. Recalled memory travels as its own delimited, tiered and budgeted contribution; interpolating it here would put it back inside an authored template, undelimited and at the system prompt's trust tier. The slots say where memory is rather than claiming there is none, which the earlier "(no prior memory context)" wording did.

build_hms_prompt_state

build_hms_prompt_state(*, domain: Any, tenant: str, tool_names: Iterable[str], domain_description: str) -> dict[str, Any]

Assemble the template state; a fresh dict on every call.

Tool names are sorted here, so the manifest does not depend on registry iteration order. Domain fields are read defensively, as the engine did, so a domain-like object missing a field falls back to that field's default.

Source code in src/symfonic/capabilities/prompting/hms_state.py
def build_hms_prompt_state(
    *,
    domain: Any,
    tenant: str,
    tool_names: Iterable[str],
    domain_description: str,
) -> dict[str, Any]:
    """Assemble the template state; a fresh dict on every call.

    Tool names are sorted here, so the manifest does not depend on registry
    iteration order. Domain fields are read defensively, as the engine did, so
    a domain-like object missing a field falls back to that field's default.
    """
    manifest = _bullets(sorted(tool_names))
    state: dict[str, Any] = {
        "TENANT_ID": tenant,
        "NAMESPACE": "",
        "TOOL_MANIFEST": manifest,
        "ACTIVE_TOOLS": manifest,
        "CURRENT_TIMESTAMP": "",
        "DOMAIN_NAME": getattr(domain, "name", ""),
        "DOMAIN_DESCRIPTION": domain_description,
        "REQUIRED_LABELS": _bullets(getattr(domain, "required_labels", ())),
        "ONBOARDING_CHECKLIST": _bullets(getattr(domain, "onboarding_checklist", ())),
        "SOUL_SCHEMA": str(getattr(domain, "soul_schema", "") or "  (none)"),
        "QUERY": "",
    }
    state.update(MEMORY_SLOTS)
    return state