Skip to content

symfonic.capabilities.prompting.composition

composition

Layering the compiled prompt onto what the phase already assembled.

Split out of :mod:.capability for the 300-line module budget; the body is unchanged.

compose_assembly

compose_assembly(context: Any, contributed: Any) -> Any

Layer the compiled prompt onto whatever the phase already assembled.

Returning contributed alone is what this capability used to do, and it silently discarded two things: Agent(instructions=...), which the kernel's own stage puts on the assembly, and any earlier capability's contribution. An adopter who passed both a prompt capability and their own instructions got only the compiled text, with nothing in the trace to say the rest had been dropped.

Order is base-then-compiled: the instructions handed to the Agent are the operator's, and the compiled layers are content this capability was configured to add underneath them.

Source code in src/symfonic/capabilities/prompting/composition.py
def compose_assembly(context: Any, contributed: Any) -> Any:
    """Layer the compiled prompt onto whatever the phase already assembled.

    Returning ``contributed`` alone is what this capability used to do, and it
    silently discarded two things: ``Agent(instructions=...)``, which the
    kernel's own stage puts on the assembly, and any earlier capability's
    contribution. An adopter who passed both a prompt capability and their own
    instructions got only the compiled text, with nothing in the trace to say
    the rest had been dropped.

    Order is base-then-compiled: the instructions handed to the ``Agent`` are
    the operator's, and the compiled layers are content this capability was
    configured to add underneath them.
    """
    prior = getattr(context, "assembly", None)
    existing = getattr(prior, "instructions", None)
    existing_blocks = tuple(getattr(prior, "system_blocks", ()))
    if not existing:
        if not existing_blocks:
            return contributed
        return replace(
            contributed,
            system_blocks=(*existing_blocks, *contributed.system_blocks),
        )
    if existing == contributed.instructions:
        # Both assemblies project the same bytes. Carrying both block lists
        # would send those bytes twice on a structured-system provider.
        return contributed
    joined = existing
    if contributed.instructions:
        joined = f"{existing}\n\n{contributed.instructions}"
    # An Anthropic breakpoint caches its prefix, including earlier system
    # blocks.  Keeping deployment instructions as their own unannotated block
    # preserves their provenance and avoids assigning *them* a cache policy;
    # it does not claim that an ensuing cached contribution excludes them from
    # the provider's cached prefix.  Earlier composed blocks already carry
    # their own annotations and must remain intact.
    prior_blocks = existing_blocks or ({"type": "text", "text": existing},)
    blocks = (*prior_blocks, *contributed.system_blocks)
    return replace(contributed, instructions=joined, system_blocks=blocks)