All checks were successful
CI / Format (push) Successful in 41s
CI / CUDA type-check (push) Successful in 1m40s
CI / Clippy (push) Successful in 2m45s
CI / Test (push) Successful in 6m14s
CI / Build cortex SRPM (push) Has been skipped
CI / Build neuron SRPM (push) Has been skipped
CI / Publish cortex to COPR (push) Has been skipped
CI / Publish neuron to COPR (push) Has been skipped
CI / Bump version in source (push) Has been skipped
CI / Format (pull_request) Successful in 39s
CI / CUDA type-check (pull_request) Successful in 1m36s
CI / Clippy (pull_request) Successful in 3m18s
CI / Test (pull_request) Successful in 7m6s
CI / Build cortex SRPM (pull_request) Has been skipped
CI / Publish cortex to COPR (pull_request) Has been skipped
CI / Build neuron SRPM (pull_request) Has been skipped
CI / Publish neuron to COPR (pull_request) Has been skipped
CI / Bump version in source (pull_request) Has been skipped
agent-zero (via litellm) drives the OpenAI Responses API and sends
`input` items in the "easy input message" form — bare `{role, content}`
objects with NO `type` field. Our `ResponsesInputItem` is internally
tagged (`#[serde(tag="type")]`), so every such item failed the untagged
`ResponsesInput` deserialize and axum's `Json` extractor returned 422:
OpenAIException - Failed to deserialize the JSON body into the target
type: data did not match any variant of untagged enum ResponsesInput
This was a *total* failure for agent-zero (both the main model on beast
and the utility model on benjy), confirmed by on-wire capture of 15 live
requests: 36/36 input items were bare easy-messages. Other clients
(/v1/chat/completions, /v1/messages) were unaffected — only the
Responses path was exercised this strictly, for the first time.
Make `input`-item parsing match OpenAI's real tolerance, mirroring the
forward-compat `extra: Value` already at the top level of the request:
- New `ResponsesInputElement` wraps the existing typed item enum with
two more shapes: `EasyMessage { role, content }` (bare, no type;
`content` optional so an assistant turn with `content: null` parses)
and `Other(Value)` — a catch-all so a single unmodeled item can never
again 422 the whole request. The typed enum is unchanged.
- `ResponsesContentPart` gains a `#[serde(other)] Unknown` arm (e.g.
`refusal`, audio) — dropped in translation, not rejected.
- `FunctionCallOutput.output` is now `Value` (string OR array of content
parts, per OpenAI) so a structured tool result isn't lost.
- Translator handles all three element shapes; easy-messages translate
exactly like typed messages, `Other` and unknown parts are dropped.
Tests cover the bare-message, null-content, unknown-item, unknown-part,
and array-tool-output shapes, validated against the 15 captured bodies.
Tools forwarding + native function_call projection on the Responses path
is deliberately a follow-up (Round 2), gated on observing how agent-zero
consumes responses once unblocked (in-band JSON vs native tool calls).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RLyKaJVFDAYnAGiLvVrK8K