Skip to content

Validate Agent configuration with official error fields - #61

Merged
SaladDay merged 5 commits into
mainfrom
codex/config-validation
Sep 23, 2026
Merged

SaladDay merged 5 commits into
mainfrom
codex/config-validation

Conversation

@SaladDay

@SaladDay SaladDay commented Sep 23, 2026 •

Copy link
Copy Markdown
Collaborator

Core-owned validation of Agent configuration (saved Agent create/update and the inline agent on Session create) now rejects what the official service rejects, with the official error fields. Native harness admission limits are unchanged. The pinned baseline is unchanged (SDK 3.13.0 / d7c41ef / agents=v1).

Behavior

  • Structural errors. Missing required parameter, unknown parameter, wrong JSON type and invalid enum value, anywhere in tools[], text.format, reasoning, service_tier, multi_agent and so on, return 400 invalid_request_error:
    • the param is the JSON path, prefixed with agent. on Session create;
    • the messages use the observed official forms, e.g. "Missing required parameter: ''.", "Unknown parameter: ''.", "Invalid type for '': expected …, but got … instead." and "Invalid value: ''. Supported values are: …";
    • supported-value lists come from the pinned enums.
  • Duplicates and member names.
    • Duplicate function names, and more than one web_search or tool_search tool, return 400 with the observed messages.
    • A repeated member, or a member name that differs from a known one only by case, returns 400 with its path. This local message was not observed officially. It stops Go's merge of repeated keys from bypassing validation.
  • Schema roots. Function parameters and text.format json_schema whose root is not type: object return the observed 400 messages, for every harness, before harness admission.
  • Session create order. An invalid inline agent is reported before the none input requirement, as officially observed.
  • Unchanged.
    • Values the official service accepts: arbitrary function names, PTC enabled on a saved Agent, reasoning.effort: max, service_tier: flex.
    • Harness admission limits, which keep unsupported_or_invalid_configuration.
    • Saved web_search modes (TV-05, pending a separate decision).
  • Echo bound. Echoed names and values are limited to 256 printable bytes.

Evidence

Campaign scan 3 findings TV-01..07 (owned official requests, all resources deleted). All 44 official TV records were replayed against this branch: 42 match on status, code, param and message, and the other 2 are the intentional K3 rows. Recorded in official-semantics-alignment.md and operation-evidence.md (entry M; rows 1, 3, 6).

Validation

  • Live check that valid configurations still execute, through real Core, the daemon and native harnesses with Kimi K3:
    • A Codex object-root function was called and completed.
    • A Claude SDK object-root json_schema answer parsed correctly.
    • These passed on both main and the candidate.
    • Invalid roots now return the new 400 on both harnesses. On main, Codex had admitted a string root.
    • 2 Turns per phase. Cleanup and secret scans passed.
  • Tests.
    • Go handler tests cover every row on Agent create, update and Session create.
    • A real-PostgreSQL replay covers two tenants and owned, foreign, missing and malformed IDs, with no-write digests.
    • The pinned-SDK scripts and the full official_client.py harness pass.
  • Server gate on the rebased code. All make check targets plus the Web typecheck, core-doctor, unit tests and build pass. The Playwright browser cases were not run on the server (no Google Chrome; skip approved by the user). make openapi is byte-identical.
  • Review. A fresh full-diff blind review by a Claude Code subagent (the user-approved replacement for GPT-6 Astra) found no K-boundary regressions. Its in-scope finding, the repeated-member bypass, is fixed in the last two commits and verified by tests and the gate.

Documented differences

  • Same-key retries of inline Sessions created before this change fail if their original configuration is now invalid; saved-Agent retries still recover.
  • An invalid inline override is reported before a missing saved Agent.

No full protocol compatibility is claimed.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith with what you need. Autofix is disabled.

Agent create and update and the inline Session agent rejected structural
configuration errors with the local unsupported_or_invalid_configuration
or invalid_request code, a null param and local messages, while the
official service reports invalid_request_error with the JSON path as
param (TV-01). Core also saved repeated function names, web_search and
tool_search declarations and non-object schema roots that the official
service rejects (TV-02, TV-03), and reported the none input requirement
before an invalid inline agent (TV-04).

A compact path-tracking validator now walks the raw JSON along the
pinned shapes (the tool unions, text, reasoning, service_tier and
multi_agent) before the existing parsers and harness admission. It
reports the first violation through the typed field error with the
observed message forms and the pinned enum lists, prefixing Session
paths with agent. Repeated tools and explicit non-object root types
return the observed messages with a null param; Session admission also
applies these checks to resolved saved configurations. Caller-supplied
names and values are only repeated when short and printable, following
the Environment Files rule.

Values the official service accepts are unchanged (TV-07), and harness
admission limits and saved web_search modes keep their local code
(TV-05, TV-06).
Replay the TV-01..03 rows on Agent create by two tenants, on updates of
owned, foreign, missing and malformed Agents, and on inline and
saved-override Session creates with and without input. Every response
must match byte for byte and a database digest must show no writes. A
saved record from before the checks cannot execute and stays invisible
to another tenant, while the K1 values are saved and read back.

The pinned-SDK acceptance scripts assert the new codes, params and
messages on Agent create, Agent update (identical for owned, foreign and
missing Agents) and inline Session create, and save function names that
the official service accepts.
Add the dated batch section to the official semantics alignment document
with rows C1-C4 and K1-K3, the scan evidence, the validator design,
message and echo decisions, and the deferred items, including TV-05.
Register the batch as Z in the operation evidence inventory and update
the Agent create, Agent update and Session create rows.

Update CONTRIBUTING, the contract README and the execution-tools,
tool-policy, structured-output and tool-search coverage where they
described repeated tools, schema roots or web_search errors as local
gaps.
The validator checked only the last copy of a repeated member, but
encoding/json merges repeated objects into the decoded pointer structs
and matches member names case-insensitively. A text object given twice
could therefore store an array-root output schema, and
{"reasoning":{"Effort":"high"},"reasoning":{}} stored effort high.

Report unknown members, including names that differ from a member only
by case, and repeated members in document order before any value is
checked, anywhere in the validated configuration tree. A repeated member
returns 400 invalid_request_error with its path as param and the local
message "Duplicate parameter: '<path>'.", since the official response
is unobserved. Members left to the existing parsers are validated on the
decoded values, so they cannot differ from what is stored.

Handler tests cover the reviewer examples on Agent create, update and
Session create with and without input, and the PostgreSQL replay proves
that they write nothing.
Replace the claim that a repeated member is checked with its last value:
unknown and repeated members are rejected in document order, with a
local duplicate message, because decoding merges repeated objects and
matches names case-insensitively.

Record that inline agent validation runs before same-key creation
recovery, so a retry of an inline Session created before this batch
returns the new 400 when its original configuration is now invalid,
while saved-Agent retries still recover. Core is pre-release, so the
order is unchanged.
@SaladDay
SaladDay merged commit cecdde0 into main Sep 23, 2026
2 of 3 checks passed
@SaladDay
SaladDay deleted the codex/config-validation branch October 7, 2026 06:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant