anthropics / anthropics/anthropic-sdk-python

output_config.format cannot take the pydantic model that output_format deprecates, and the dict workaround silently skips transform_schema

Đang mở
#1,819 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
Python
Star
3.9k
Fork
853
Merge trung bình
1 ngày 11 giờ
Pull request đã merge (30 ngày)
10

Mô tả

## Summary

On `anthropic==0.121.0`, passing `output_format=` to the beta messages resource emits

> `DeprecationWarning: The 'output_format' parameter is deprecated. Please use 'output_config.format' instead.`
> — `resources/beta/messages/messages.py:4229`

but `output_config.format` **cannot accept a pydantic model**, which is the input form
`output_format=` exists for. Following the warning literally raises `TypeError`, and the
natural workaround (hand it `Model.model_json_schema()` as a dict) silently **skips
`transform_schema`** — so migrating changes the schema that goes on the wire.

## Repro

Executed as written against `anthropic==0.121.0` / `pydantic==2.13.4`, with
`httpx.Client.send` patched to capture the request body and return a 401 (no API key,
nothing leaves the machine).

```python
class Item(BaseModel):
code: str = Field(pattern=r'^[A-Z]{3}$', min_length=3)
```

**A — the deprecated form.** Warns, and `transform_schema` runs:

```json
{"type":"object","title":"Item",
"properties":{"code":{"type":"string","title":"Code",
"description":"{minLength: 3, pattern: ^[A-Z]{3}$}"}},
"additionalProperties":false,"required":["code"]}
```

**B — the migration the warning names.** `output_config={"format": Item}`:

```
TypeError: Object of type ModelMetaclass is not JSON serializable
```

**C — the workaround**, `output_config={"format": {"type":"json_schema","schema": Item.model_json_schema()}}`:

```json
{"properties":{"code":{"minLength":3,"pattern":"^[A-Z]{3}$","title":"Code","type":"string"}},
"required":["code"],"title":"Item","type":"object"}
```

C is **not** A. `additionalProperties: false` is gone, and `minLength`/`pattern` are no
longer folded into `description`. So a user who follows the deprecation notice stops
getting the normalization the SDK applies today, with no error and no warning.

## Cause

`transform_schema` runs only on the `elif` branch of

```python
if is_dict(output_format): # beta messages.py:1769, :3778
transformed_output_format = cast(...) # cast through, untransformed
elif is_given(output_format) and output_format is not None:
schema = adapted_type.json_schema()
transformed_output_format = JSONOutputFormatParam(schema=transform_schema(schema), ...)
```

`output_config` has no equivalent branch at all — its `format` is forwarded as given, so
every form of it is untransformed. Measured across `create` / `parse` / `stream` and both
the beta and non-beta resources: `output_config.format` never transforms.

Two smaller notes from the same measurement:

- The DeprecationWarning fires on the **beta** resource only. `messages.parse`,
`messages.stream` and `messages.count_tokens` on the non-beta resource accept
`output_format=` silently, so the two resources disagree about whether this parameter
is deprecated.
- `count_tokens(output_format=)` is also untransformed while
`count_tokens(output_format=)` is transformed, so a token count taken via the
dict form is counting a different document than the one `parse()` would send.

## Suggested shape of a fix

Either route `output_config.format` through the same branch (accept a type there and
transform it), or state in the deprecation message that `output_config.format` takes a
pre-built `json_schema` dict and applies no transform — the current wording implies a
drop-in rename, and it is not one.

## Test-design warning

A regression test that asserts only "the request was built" cannot see this — the
request builds fine in both A and C. It has to assert on the **emitted schema**. And a
fixture whose model carries no constrained fields is weaker than it looks: it will still
differ on `additionalProperties`, but nothing else, so the demotion half of the change
goes untested. Use a field with `pattern=`/`min_length=` as above.

## Scope

No API key was used, so this is entirely about the request the SDK builds; I am not
claiming anything about how the service treats either payload.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Hướng nghiên cứu

Start in resources/beta/messages/messages.py at the referenced lines around 1769, 3778, and 4229, then compare output_config.format with output_format across create, parse, stream, and count_tokens in both resources. Use the constrained Pydantic model from the report and assert on the emitted schema; done means the migration path and its warning behavior are consistent without silently changing transformation.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
python
Lĩnh vực
api, testing
Loại issue
Lỗi
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Ít trao đổi
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
58/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.