symfonic.evals.content_packs¶
content_packs ¶
Optional packs for what a turn carries in and what it must hand back.
Three families, and only one of them is gated on a capability name:
- knowledge grounding needs
promptingand theknowledge.sourcestrait. Knowledge is deliberately not its own capability -- sources are what the prompting capability compiles -- so a pack that required aknowledgename would report a capability no deployment can compose and would never run. But the name alone is the umbrella the review caught:PromptingCapability(sources=[])foldspromptingand compiles nothing, and a grounding pack run against it asserts that answers came from a corpus that does not exist. The trait is the compiled region count off the agent-attested fold, so an empty capability resolves to not-applicable by name. - structured output and multimodal attachments are gated on the turn
inputs the compiled agent accepts, because neither composes a capability at
all:
output_typeandattachmentsare parameters of the public turn. Inventing a capability name for either would claim the default scaffold composes something it does not.
The gate is therefore whether the target can deliver the step. The shipped JSON chat API accepts a query and nothing else, so both packs resolve to not-applicable against it by name, rather than failing on the delivery and looking like a behaviour regression.
knowledge_grounding_pack ¶
knowledge_grounding_pack(evidence: CapabilityEvidence, *, grounded_prompt: str, grounded_fragments: Sequence[str], source_fragment: str, unsupported_prompt: str, refusal_fragments: Sequence[str], context_attribute: str = 'prompt_context', conversation: str = 'knowledge', policy: TrialPolicy = _DEFAULT_POLICY, source_trait: str | None = None) -> PackResolution
Answer from the composed sources, and decline outside them.
Two steps, because either one alone is passable by an agent that is broken in the other direction: a corpus answer proves nothing about fabrication, and a refusal proves nothing about retrieval. The first also requires the source text in the compiled context -- an answer that was right while the source never reached the prompt was right from the model's weights, and will stop being right when the corpus changes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source_fragment
|
str
|
text the composed knowledge source contributes, as it must appear in the model's input. |
required |
refusal_fragments
|
Sequence[str]
|
how this deployment declines. Its own wording, not a phrase invented here. |
required |
Source code in src/symfonic/evals/content_packs.py
multimodal_attachment_pack ¶
multimodal_attachment_pack(evidence: CapabilityEvidence, *, prompt: str, attachments: Sequence[Any], delivered_media_types: Sequence[str], expected_fragments: Sequence[str] = (), delivery_attribute: str = 'attachment_delivery', conversation: str = 'multimodal', policy: TrialPolicy = _DEFAULT_POLICY) -> PackResolution
Require the attachment to reach the provider, not the call to be accepted.
Agent.run(attachments=[...]) returning without raising proves the
signature; it does not prove a block was built or that it carried the
bytes, and a dropped attachment produces a confident answer about a
picture the model never saw. So the assertion is on delivery evidence the
target publishes from the outgoing side of the turn, and the response
check is additional rather than sufficient.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
delivered_media_types
|
Sequence[str]
|
exactly the media types the wire must carry, in attachment order. Retained as a declaration check; delivery itself is asserted with ordered payload-safe content digests. |
required |
delivery_attribute
|
str
|
where the target publishes what actually went out. |
'attachment_delivery'
|
Source code in src/symfonic/evals/content_packs.py
structured_output_pack ¶
structured_output_pack(evidence: CapabilityEvidence, *, prompt: str, output_type: type[Any], expected: Mapping[str, Any] | None = None, conversation: str = 'structured', policy: TrialPolicy = _DEFAULT_POLICY) -> PackResolution
Require a validated instance of the declared schema, not prose about it.
StructuredOutputMatches reads the target's validated value, so a
fluent JSON-shaped answer that never reached the schema fails here.
Source code in src/symfonic/evals/content_packs.py
viewable_tool_result_pack ¶
viewable_tool_result_pack(evidence: CapabilityEvidence, *, tool_name: str, first_prompt: str, follow_up_prompt: str, expected_fragments: Sequence[str], arguments: dict[str, object] | None = None, conversation: str = 'viewable-result', policy: TrialPolicy = _DEFAULT_POLICY) -> PackResolution
A tool result the model can look at must still be lookable at later.
One turn proves nothing: compaction rewrites results that have settled,
so the failure is on the second turn. It replaced an image block with a
text stub and offered recall returning str, and the model then answers
about the picture from a description of it, which reads exactly like an
answer about the picture (#144).
Hence two steps in one conversation: the first calls the tool, the second
asks something only the image can settle. expected_fragments must name
something legible only from the image and never a value the first answer
already stated, or the model can reconstruct it from its own prose.