agentkit.agents.prompts¶
Versioned Prompt value type and the built-in prompts used by shipped
cognitions.
See the Prompts concept for the mental model.
agentkit.agents.prompts — the prompt-management skeleton.
The framework defines WHAT a prompt is. Applications own storage, discovery, resolution, and any validation/evaluation contracts they choose to add — those don't belong in the framework's public surface unless the framework actually dispatches them.
The skeleton:
- Prompt (data type) — id + version + template + bind() + render()
- builtin — the framework's own seed prompts (Compactor)
Why no validator/evaluator skeleton: exporting Validator /
PromptEvaluator type aliases the framework never dispatches would
imply a runtime validation surface that doesn't exist. The Agent's
parse-and-repair uses its own SchemaAdapter path. Apps that need
that pattern ship their own shapes.
Why no store/registry/resolver: prompts are code (defined as constants, version-controlled in git). Apps that need runtime mutation, dynamic loading, or a UI to inspect prompt history ship their own infrastructure on top of this skeleton.
Prompt
dataclass
¶
Prompt(
id: str,
version: str,
template: str,
inputs: tuple[str, ...] = tuple(),
bound: Mapping[str, Any] = FrozenDict(),
)
A versioned system prompt. The version label travels with every
output the prompt produces (stamped via RequestBuilder onto
AgentResult + traces), so a regression in quality maps back to a
specific template version.
inputs
class-attribute
instance-attribute
¶
The placeholder names template declares, e.g. ("tenant", "tone")
for a template containing {tenant} and {tone}. Declared on the value
so a caller can validate a prompt against its call site before a run, and so
a stored prompt carries its own contract.
bound
class-attribute
instance-attribute
¶
Values already bound to the declared inputs. Normally set via
:meth:bind rather than passed to the constructor. Because the values live
on the value, a bound Prompt renders with no arguments — which is what
lets every consumer in the framework (RequestBuilder, the CLI cognitions)
keep calling render() with nothing while still shipping substituted
text. Frozen to a read-only mapping in __post_init__.
bind
¶
bind(**values: Any) -> Prompt
Return a copy of this prompt with values bound to its inputs.
The prompt is frozen, so this never mutates — it hands back a new value,
which is the point: a bound prompt is still a pinnable, diff-able
Prompt carrying the same id / version, and can be handed
anywhere an unbound one goes (Agent(prompt=...), RequestBuilder).
Binding is incremental and last-write-wins, so partial binding at construction and the rest at the call site both work::
p.bind(tenant="acme").bind(tone="terse") # == p.bind(tenant="acme", tone="terse")
An undeclared name raises ValueError HERE rather than at
render() — the earlier the typo surfaces, the cheaper it is.
render
¶
Substitute the declared inputs and return the prompt text.
Values come from :meth:bind and/or from **values here, with
**values winning on a collision (a per-call override of a bound
default). With no inputs declared this is what it has always been —
the stripped template — so every existing caller is unaffected.
Substitution is a literal replacement of {name} for each DECLARED
input, never str.format. That is deliberate: system prompts are full
of braces that are not placeholders — a JSON Schema, an example payload,
a code fence — and format would either raise KeyError on them or
silently eat the doubling a user added to escape them. Replacing only
the names the prompt declared leaves every other brace untouched.
Raises ValueError when an input is neither bound nor supplied,
rather than rendering a half-filled prompt. A {tenant} that reaches
the model unsubstituted is not a crash, which is exactly the problem: it
is a plausible-looking prompt that quietly describes the wrong task.
compose
¶
compose(
parts: Sequence[PromptPart],
inputs: Mapping[str, Any],
*,
max_chars: int = 200000,
persona_screening: Callable[[str], str] | None = None,
images: Sequence[ImagePart] = (),
) -> ComposedPrompt
Render every part strictly, refuse overflow, and keep untrusted text in user content.