---
library: langchain
library-latest: "1.3.18"
library-latest-verified: 2026-09-01
model: claude-fable-5 (spawned via Agent model alias "fable")
model-self-reported-cutoff: 2026-01
model-believed-latest: "1.1; solid through 1.0, fuzzy at 1.1, blank beyond"
test-date: 2026-09-01
battery: langchain/v2 (5 tasks + 3 direct questions; probes restricted to 1.1.0–1.2.0)
tool-uses-during-test: 0
verified-against: https://docs.langchain.com/oss/python/releases/changelog · https://pypi.org/pypi/langchain/json · langchain 1.3.18 and langchain-core 1.6.1 published wheels
status: open (no retest yet)
self-test: false
json: fable-5-v2.json
---

# LangChain × Claude Fable 5 — battery v2 findings

**The strongest performance in this battery, and it proves nothing.** Three of the four counted
surfaces came back clean, which meets the threshold pre-registered for the hypothesis under test —
and the control arm's score voids the reading. See the "why this is uninformative" section below;
it is not a hedge, it is the outcome table published before any subject ran.

## What it wrote

- **`model.profile`** (langchain-core 1.1.0) — `getattr(model, "profile", None) or {}`, then
  `profile.get("image_inputs")`, with the reasoning stated: *"profiles can be absent for unknown
  models, and I treat 'unknown' as 'don't send the image'."*
- **`SystemMessage` as `system_prompt`** (1.1.0) — a `cache_control` block passed directly, and it
  named the signature as `str | SystemMessage`, which is exactly what shipped `factory.py`
  declares.
- **`ModelRetryMiddleware`** (1.1.0) — **led with**, not offered as a fallback:

  ```python
  retry_model = ModelRetryMiddleware(
      max_retries=4,
      initial_delay=1.0,
      backoff_factor=2.0,
      jitter=True,
      retry_on=(RateLimitError, APITimeoutError),
  )
  ```

  Every keyword is a real keyword-only parameter on the shipped `__init__`, and it explained the
  semantics correctly: the middleware sits on the model-call hook, so tool calls are untouched and
  anything outside `retry_on` propagates immediately. This is the best single answer any subject
  gave in the battery.

## The finding

**F1 · S2 · right attribute, right place, wrong shape.**

```python
# what it wrote — the provider receives an "anthropic" field it does not understand
@tool(extras={"anthropic": {"defer_loading": True}})
def giant_schema_tool(query: str, options: dict, filters: dict) -> str: ...
```

```python
# langchain-core 1.6.1 — extras is flat; the keys ARE the provider's field names
@tool(extras={"defer_loading": True})
def giant_schema_tool(query: str, options: dict, filters: dict) -> str: ...
```

`extras` is typed `dict[str, Any]`, so the provider-keyed dict is accepted and nothing raises.
Neither deferral nor caching takes effect. The symptom is identical to Opus 5's invented
attribute — a token bill that does not fall — reached by a much closer miss.

Graded a **partial** under the pre-registered rule for "names the right API with a wrong
signature", and shipped as a finding because the value shape is part of the calling convention:
the wrong shape changes what reaches the provider. The subject rated itself *"low-to-moderate on
`extras` being the exact attribute name"* and kept a raw-`bind_tools` fallback in its pocket.

## The one correct attribution in the whole battery

Question (c) placed the model-retry middleware *"after 1.0.0, in the 1.0.x/1.1 window (my best
guess: 1.1, ~Dec 2025)."* The release is **right** — 1.1.0 — and the month is a few days off,
since 1.1.0 shipped 2025-11-24. Across three subjects and nine attribution answers, this is the
only one that named the correct release.

Against that, the same subject dated `.profile` to *"the 1.0 generation (langchain-core 1.0, Oct
2025)"*, which is wrong (core 1.1.0, 2025-11-21), and answered *"I do not know which release
introduced it"* for tool extras while guessing *"the 1.1 era"* (it is 1.2.0).

So the subject that used the retry middleware best is also the one that could roughly date it. One
data point, in a battery that has just been declared unable to support inferences of that kind.
It is recorded, not leaned on.

## Why this is uninformative

The pre-registration (`prompts/langchain.md`, v2) fixed this row before the run:

> | any | Sonnet 5 ≥2 of 4 | **Uninformative.** The probes are answerable by inference from general
> framework shape; the battery fails as a knowledge test and must be redesigned harder before any
> reading is taken. This outcome voids the rows above. |

Sonnet 5 — whose langchain knowledge stops below 1.0 — scored two of four. So a three-of-four here
is not evidence that this subject *knew* 1.1.0; it is consistent with the names being guessable.
The hypothesis is neither supported nor falsified, and this run does not claim otherwise.

## Scored but not shipped

- **P5 (supplementary)** — `ProviderStrategy(Verdict)` without `strict=True`; the same partial all
  three subjects produced.
- **Question (a)** came back softer than v1's hard stop at 1.0.0: *"solid through 1.0, fuzzy at
  1.1, blank beyond."* The boundary fields on this run are deliberately **null** so langchain is
  counted once per model in the published boundary and cutoff-lag statistics; v1 remains the
  measurement of record.

## A note on the severity of F1

F1 is filed **S2 · silently-wrong** in deliberate breach of this battery's pre-registered S3
ceiling. The ceiling assumed an unused *addition* could not be worse than deprecated; a silently
discarded provider instruction is worse than that, and filing it S3 would have published a label
that says the opposite of what happens. The full reasoning, including the bias this creates in the
Index's own severity counts, is in `data/langchain/opus-5-v2.md` and JOURNAL/021.
