Skip to content

Move dry_run_role off public LLMClientConfig schema #63

Description

@dantp-ai

Context

PR #62 added a dry_run_role: str | None = None field to LLMClientConfig in clawloop/train.py:39-42 so that clawloop run --dry-run can identify which mock client to substitute for each role. This was chosen over the prior approach (mutating LLMClientConfig.model with a marker string) on reviewer feedback (PR #62 review comment 1) because mutating model could pollute downstream consumers like _build_entropic, which reads tc.model and propagates it into entropic_cfg.

The current design works and is well-tested (tests/test_cli.py::test_dry_run_role_field_survives_pydantic_copy), but it still has a minor smell flagged in self-review: a CLI testing affordance now lives on a public Pydantic model. Every model_dump_json() of a TrainConfig emits \"dry_run_role\": null for each LLM client. JSON Schema generators surface it. Future config-validation UIs see it.

Proposal

Move the role mapping into a side-channel owned entirely by clawloop/cli.py:

# in cli.py
from weakref import WeakKeyDictionary

_dry_run_roles: WeakKeyDictionary[LLMClientConfig, str] = WeakKeyDictionary()

_install_dry_run_clients populates this dict; the patched _make_llm_client reads from it via _dry_run_roles.get(cfg). This:

  • Removes dry_run_role from the public LLMClientConfig schema entirely
  • Survives Pydantic model_copy() the same way the field does, as long as the original object stays referenced (it does — config.llm_clients holds it)
  • Keeps all dry-run vocabulary in cli.py where it belongs

Trade-off: WeakKeyDictionary requires the cfg objects to be hashable. Pydantic v2 models are hashable by default, so this should work.

Acceptance

  • LLMClientConfig no longer carries dry_run_role
  • model_dump_json() of LLMClientConfig does not emit any dry-run markers
  • All existing dry-run smoke tests still pass (test_run_*_dry_run_*, test_dry_run_role_*_survives_pydantic_copy)
  • The Pydantic-copy test is rewritten to assert the side-channel survives copies

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions