Consume the typed RendererConfig surface#1467
Conversation
Replaces the flat ``renderer``, ``tool_parser``, ``reasoning_parser``, ``preserve_*`` fields on ``ClientConfig`` with a single typed ``renderer_config: RendererConfig | None`` field. The discriminated union exposes exactly the kwargs each renderer's chat template honours, so a TOML / Python user picks ``Qwen35RendererConfig(enable_thinking=False)`` instead of feeding flat strings into a runtime-validated allowlist. ``renderer_model_name`` / ``renderer_pool_size`` stay as separate fields: they're orthogonal to the renderer choice itself. ``RendererClient._get_renderer_or_pool`` simplifies to passing the typed config straight through to ``create_renderer_pool(model, config)``. Cache key collapses from a 7-tuple of flat fields to ``(model, pool_size, config_json)``; the typed config is frozen and hashable but we serialise it for a deterministic key shape that's stable across pydantic version bumps. Pins ``renderers`` to a git SHA on ``feat/chat-template-kwargs-renderers`` until that PR merges and a dev release ships. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ApprovabilityVerdict: Needs human review This PR makes a breaking API change to You can customize Macroscope's approvability policy. Learn more. |
The typed-config refactor landed on renderers main as ``c86c50b`` (tag ``renderers-v0.1.8.dev27``). Switching the git URL pin from the pre-merge feature-branch SHA to the dev tag — same commit, more readable, and stable to anyone reading the diff after the feature branch is deleted. PyPI dev release for the same version is pending a publisher-config fix; once it lands this can collapse to a plain ``renderers>=0.1.8.dev27`` PyPI pin.
``from renderers import RendererConfig`` at the top of types.py made ``import verifiers`` fail with ``ModuleNotFoundError`` whenever the optional ``[renderers]`` extra wasn't installed, because ``verifiers/__init__.py`` eagerly runs ``from .types import *``. Move the import under ``TYPE_CHECKING`` for static analysis and try-import at runtime with an ``Any`` fallback. Pydantic still validates the discriminated union when renderers is present; when it isn't, the field accepts anything (the default ``None`` is what non-renderer clients use, and the renderer client only loads when renderers is installed). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the git-URL pin (introduced when the dev release was waiting on PyPI trusted-publisher config) with a regular PyPI dependency. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1a406bf. Configure here.
``uv lock`` after switching from the git-URL renderers pin to PyPI (``renderers>=0.1.8.dev27``). Also reformats one line in ``renderer_client.py`` that drifted past ruff's line length. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dev28 (renderers#64) lazy-loads concrete renderer classes via PEP 562, so consumers of just the typed ``RendererConfig`` discriminated union don't pull ``transformers`` into ``sys.modules``. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
``renderers/client.py`` switched to parsing the raw response bytes (``raw_response.content``) when routed-experts sidecar support landed (renderers PR #21 / 3177399). The e2e test's ScriptedVLLM still returned the parsed dict directly, so ``parse_generate_response`` hit ``AttributeError: 'dict' object has no attribute 'content'`` on every rollout and the trajectory came back empty. Wrap the canned payload in ``_ScriptedResponse`` whose ``.content`` is the JSON-encoded bytes, matching what ``httpx.AsyncClient.post`` actually returns. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ass-through-info-2026-05-19 Resolved conflicts in pyproject.toml, tests/test_renderer_e2e.py, and uv.lock by taking main's side: renderers >=0.1.8.dev28 and the typed RendererConfig surface from #1467 (config_from_name(...), _ScriptedResponse). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Summary
Switches
ClientConfigandRendererClientto consume the typedrenderers.RendererConfigdiscriminated union (rendered inPrimeIntellect-ai/renderers#60).
renderer,tool_parser,reasoning_parser,preserve_*fields fromClientConfig.renderer_config: RendererConfig | Nonefield. Pydantic dispatches on thenamediscriminator ("qwen3","glm-5", …) and exposes exactly the kwargs that renderer supports.renderer_model_name/renderer_pool_sizestay as separate fields — they're orthogonal to the renderer choice._get_renderer_or_poolcollapses tocreate_renderer_pool(model, config). Cache key shrinks from a 7-tuple of flat fields to(model, pool_size, config_json).API
Before:
After:
Bogus combinations (e.g.
add_vision_idundername="qwen3") raise apydantic.ValidationErrorat config-load time instead of at renderer construction.Stacking
Pins
renderersto a git SHA on the renderers PR's head while it's in review. When that lands and a new dev release ships, this PR bumps to the PyPI release.chat_template_kwargsthroughsampling.extra_body)Validation
Static-only at the moment — the renderers branch hasn't shipped to PyPI, so the verifiers venv can't be re-synced to run pytest against the new typed surface yet.
uv run ruff check ...— cleantest_renderer_client.pyupdated to construct typed configs; will run on CI after the renderers dep resolves.Test plan
rendererstyped-config branch is available (either merged + dev release, or the git pin resolves in the lockfile)ClientConfigthrough TOML → pydantic →_get_renderer_or_pooland confirm the typed config flows throughNote
Medium Risk
Breaking change to renderer
ClientConfigshape and shared-pool cache keys; rollout configs must migrate before deploy, and pool reuse behavior may differ for equivalent old flat settings.Overview
Replaces flat renderer client settings with a typed
renderers.RendererConfigobject onClientConfig, and threads that object throughRendererClientpool creation.ClientConfigdropsrenderer,tool_parser,reasoning_parser,preserve_all_thinking, andpreserve_thinking_between_tool_callsin favor ofrenderer_config: RendererConfig | None(optional import whenverifiers[renderers]is not installed).RendererClientnow callscreate_renderer_pool(model, renderer_config, …)and keys shared pools on(renderer_model_name, pool_size, renderer_config.model_dump_json())instead of the old seven-field tuple—so pool sharing follows the full serialized config, not separate parser/preserve flags.Dependency and test alignment:
renderersis pinned to>=0.1.8.dev28(with lockfile updates forfastokens,prime-pydantic-config, and removal oftyro/typeguardtransitives). Tests construct typed configs (e.g.Qwen3VLRendererConfig) and useconfig_from_name()withcreate_renderer. E2EScriptedVLLMreturns an httpx-like response whose.contentis JSON bytes forparse_generate_response.Migration: configs must use discriminated renderer config objects (e.g.
Qwen35RendererConfig(...)) instead of stringrendererplus loose kwargs; invalid field combinations fail at Pydantic validation time.Reviewed by Cursor Bugbot for commit fa4652a. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Replace renderer string fields with typed
RendererConfiginClientConfigrenderer: str,tool_parser,reasoning_parser,preserve_all_thinking, andpreserve_thinking_between_tool_callsfields inClientConfigwith a singlerenderer_config: RendererConfig | Nonefield from therendererspackage.RendererClient._get_renderer_or_poolto pass the typed config object directly tocreate_renderer_pool, keying the shared pool cache on(renderer_model_name, pool_size, renderer_config_json)instead of the previous 7-tuple.config_from_name(renderer_name)when constructing renderers from a string name.renderer_configJSON, which may change pool-sharing behavior for existing configurations.Changes since #1467 opened
rendererspackage an optional dependency forverifiers.typesmodule by conditionally importingRendererConfig[f322bc9]renderersdependency specification from Git VCS URL to PyPI version constraint in optional dependency groups [1a406bf]rendererspackage dependency constraint to version>=0.1.8.dev28[d107442]_ScriptedResponseclass and modifiedScriptedVLLM.postmethod to return response objects [fa4652a]Macroscope summarized 5727298.