Skip to content

docs: clarify format= value contract and model_validate_json pattern#1333

Merged
planetf1 merged 3 commits into
generative-computing:mainfrom
planetf1:docs/format-value-contract
Jun 24, 2026
Merged

docs: clarify format= value contract and model_validate_json pattern#1333
planetf1 merged 3 commits into
generative-computing:mainfrom
planetf1:docs/format-value-contract

Conversation

@planetf1

Copy link
Copy Markdown
Contributor

Closes #1273. Closes #1274.

Supersedes #1284, which attempted a code-level fix. The maintainer decision
is to document the behaviour clearly instead.

What this PR does

format= on act/aact/instruct/ainstruct constrains the backend's
token generation to JSON matching the declared Pydantic schema. The thunk's
.value is always a str — not a parsed model instance. The previous docs
only hinted at this in a terse comment; callers had to guess the parse step
and could silently introduce a cast footgun.

docs/how-to/act-and-aact.md

  • Rewrites the Structured output section with a complete working example
    (schema definition → act() call → model_validate_json parse)
  • Adds a callout explaining the design contract, naming the cast footgun
    explicitly (cast(Planet, result.value) passes type checking but raises
    AttributeError at runtime), and covering the return_sampling_results
    unwrap variant
  • Adds a one-sentence note to the aact() section confirming the same
    contract applies there

docs/how-to/enforce-structured-output.md

  • Merges instruct(format=...) and act(format=...) into a single table
    row (they share the same contract)
  • Adds a cast warning callout to Pattern 2 with the return_sampling_results
    unwrap note
  • Updates the "Choosing between" section to mention act(format=...) directly

Docstrings (mellea/core/base.py, mellea/stdlib/session.py, mellea/stdlib/functional.py)

  • ComputedModelOutputThunk.value — expanded from "Gets the value of the
    block" to describe the JSON-string contract and the parse step
  • format parameter — updated in act, aact, instruct, ainstruct
    (both session.py and functional.py) from "BaseModel for constrained
    decoding" to include the .value-is-str contract and the
    model_validate_json pattern

Why not a code fix?

A code fix (#1284) was explored and declined in review. The design intent is
that format= is a generation hint, not a typing signal: a component
declares the shape of its output (e.g. a Message component returns a
Message), and format= is a separate concern. The clean code-level path
is @generative, which returns a typed instance directly. The docs now say
this clearly.

The type-narrowing gap (#1274) remains open as a future improvement,
tracked in #1313.

`format=` on act/aact/instruct/ainstruct constrains token generation to
JSON matching the Pydantic schema. The thunk's `.value` is always a str,
not a parsed model instance — callers must parse explicitly:

    planet = Planet.model_validate_json(str(result))

The previous act-and-aact.md example only hinted at this in a comment.
This change makes the full pattern visible in working code, adds a
callout noting that `cast(Planet, result.value)` silently type-checks
but fails at runtime, and covers the async and sampling-result variants.

enforce-structured-output.md now mentions act(format=...) alongside
instruct(format=...) in the table and choosing-between sections, and
adds the same cast warning to Pattern 2.

Docstrings for format= in act/aact/instruct/ainstruct (both session.py
and functional.py) and ComputedModelOutputThunk.value (base.py) are
updated to match.

Closes generative-computing#1273. Closes generative-computing#1274.

Assisted-by: Claude Code
Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>
planetf1 added 2 commits June 24, 2026 10:41
Post-review polish from independent 3-reviewer pass:

- Replace RST double-backtick literals (``x``) with plain single-backtick
  inline code (`x`) in all eight format= docstrings (functional.py, session.py)
  and the ComputedModelOutputThunk.value docstring — AGENTS.md §5 prohibits
  RST markup inside docstrings
- In base.py, replace `self.value` example with `str(result)` to match the
  pattern used consistently across all user-facing docs
- Drop redundant "If set," prefix from format= docstrings — the optional nature
  is already declared in the signature; "Constrains generation to..." is cleaner
- enforce-structured-output.md: tighten "same contract" to "same JSON-string
  contract" so the cross-reference is self-explanatory

No functional changes; documentation/docstring only.

Assisted-by: Claude Code
Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>
…in table

The intro table was mixing two concerns — when to choose a pattern and
what each pattern returns. Split them:

- Strip both rows to pure selection criteria
- Add a prose sentence below the table stating the contract difference:
  @Generative returns the Pydantic instance directly; instruct/act(format=...)
  return a thunk whose .value is a JSON string to parse with model_validate_json

Assisted-by: Claude Code
Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>
@planetf1
planetf1 marked this pull request as ready for review June 24, 2026 09:49
@planetf1
planetf1 requested review from a team, jakelorocco and nrfulton as code owners June 24, 2026 09:49
@planetf1
planetf1 requested a review from ajbozarth June 24, 2026 09:49
@planetf1
planetf1 enabled auto-merge June 24, 2026 10:00
@planetf1
planetf1 added this pull request to the merge queue Jun 24, 2026
Merged via the queue into generative-computing:main with commit 70d9f5f Jun 24, 2026
9 checks passed
@planetf1
planetf1 deleted the docs/format-value-contract branch June 24, 2026 16:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

2 participants