prompt_sections_lab¶
Low-level lab — build a system prompt from sections you write yourself.
This is a lab, not a rung. It works one level below Agent and
PromptingCapability: those compile a prompt from contributed sources and are
what an application should use. PromptBuilder is the machinery underneath,
and it is public because a deployment sometimes needs to build a prompt outside
a turn — to render one for review, to diff two, or to test a section alone.
- Lines: ~120
- Prerequisites: none
- Key concepts:
PromptBuilder,PromptSection, section priority, empty sections
What it shows¶
A section is a protocol, not a base class. PromptSection is
@runtime_checkable with four attributes and one coroutine, so the three
sections in this file prove they conform with isinstance and inherit
nothing. The concrete sections the framework ships are internal on purpose:
what is public is the shape, so the sections you write are first-class
rather than second-best.
Priority orders the output, not the list. Lower is earlier. The lab adds
Memory first and it renders last, which is the one thing worth getting
wrong once here rather than in a prompt nobody can read.
A section with nothing to say says nothing. An empty section that still renders its heading costs a delimiter and tells the model the store was consulted and found empty — a different claim from not having consulted it.
Where it came from¶
Extracted from e2e_basic_agent, which is archived. That example was four
demos in one file: this one, stream-event processing, a capability timeout,
and an agent run. Three of the four reached into internal submodules
(symfonic.core.prompt.sections, symfonic.core.streaming.event_processor),
and the agent demo was already journey_stateless.
Keeping it would have meant promoting those submodules to the public surface — turning implementation detail into a permanent commitment to hold an internal shape still. The lesson worth keeping is here instead, rewritten against the contract rather than against the framework's own section classes.
Import from the package root¶
symfonic.core.prompt, symfonic.core.prompt.blocks and
symfonic.core.prompt.blocks.sources are public, and each defines an
__all__ that is the contract. Their submodules are internal. A project
that imports from a submodule will fail its own generated
tests/test_public_api_imports.py.
Related¶
- Prompting capability — what an application should use
- block_boundaries — the block surface, one level further down