Skip to content

Serialize code-derived values as raw strings - #778

Open
eb8680 wants to merge 1 commit into
worktree-issue-763-no-encoding-schemafrom
worktree-issue-775-raw-string-code
Open

Serialize code-derived values as raw strings#778
eb8680 wants to merge 1 commit into
worktree-issue-763-no-encoding-schemafrom
worktree-issue-775-raw-string-code

Conversation

@eb8680

@eb8680 eb8680 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Resolves #775 , blocked by #770

This pure-refactoring PR implements the suggestion in #775 to remove the junk Pydantic intermediates in code generation. The diff looks bigger than it is because of reindentation and needing to propagate the schema change to test fixtures, but it's conceptually just replacing SynthesizedFunction et al with Annotated[str, BeforeValidator(...)] and should be completely semantics-preserving, including what is shown to the model in the schema. It also eliminates some redundant types and docstrings.

This would be even cleaner in conjunction with #765 but it shouldn't be blocked by that.

A synthesized function crossed the model boundary as source escaped inside a
JSON object -- `{"code": ...}`, via the `EncodedFunction` model on the way out
and the `SynthesizedFunction` family on the way in. Providers that decode
structured output approximately (ds4) have to get that escaping right by hand,
and the wrapper dragged a `$defs`/`$ref` into every schema mentioning a
callable. Generalize what `synthesis.snippet` already does for `types.CodeType`:
a bare `str`, with `BeforeValidator`/`PlainSerializer` doing the work.

`EncodedFunction` becomes an `Annotated[str, Field(...)]`, and the
`SynthesizedFunction`/`SynthesizedSkillBody`/`SynthesizedMethodSkillBody`
hierarchy flattens into `_signature_str`, `_synthesized_source_schema` and
`_checked_source`. The prose those classes carried was split across a model
docstring and a field description, which the single string schema merges: the
signature line and all five constraints survive, and constraints 1-3 -- until
now repeated verbatim at three sites -- are stated once. The method body's
`_extra_instructions` is dropped as the third statement of its `self` receiver,
which the rendered `Callable[[self, ...], R]` and constraint 4 both still make.

A prompt-spliced function now also reaches the model as unencoded source rather
than escaped inside a string, which `to_content_blocks` gets for free once the
encoding is a top-level string.

The replay fixtures are migrated rather than re-recorded: `REBUILD_FIXTURES`
cannot run, because `ReplayLiteLLMProvider._completion` forwards `fwd(*args,
**kwargs)` without `model` and litellm rejects the call. That fails identically
on the base branch, so it is a separate bug; only each fixture's JSON envelope
is rewritten, and every recorded source string is preserved byte for byte.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Code-derived inputs and outputs should be serialized as raw strings

1 participant