Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ to recover a lost creation response. Session metadata updates require a supplied
metadata field, with null/empty clearing it. Validate an empty update before any
resource lookup, after authentication.

List order parsing distinguishes omission from an explicit empty value. Reuse the
shared parser and error serializer, preserving the observed Beta, Files and Skills
error fields rather than applying one error code to every resource. Qualification
of one query error does not authorize changing page bounds, cursor ownership or
parent lookup order. Record uncertain range/lookup behavior separately; do not
reproduce observed upstream server failures as compatibility behavior. See
`contracts/agents-api/list-query-semantics.md` for the bounded evidence.

Keep runtime state, test artifacts and build output under `~/.parsar/`. Require
absolute user-supplied working directories. Keep credentials out of source and
logs. Update this guide when architecture, ownership or generated contracts change.
Expand Down
2 changes: 2 additions & 0 deletions contracts/agents-api/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Agents API contract

See the [58-operation evidence inventory](operation-evidence.md) for observed official behavior, local verification and remaining unknowns.
The [list-query comparison](list-query-semantics.md) distinguishes measured order
errors from unresolved range, cursor and lookup semantics.
The external reference is [openai-python beta/agents](https://github.com/openai/openai-python/tree/d7c41efee1b0802b79f3f88a678ef2052b06e9ce/src/openai/resources/beta/agents),
pinned in `upstream.json`. Its resource methods, corresponding types, pagination
and streaming helpers define the compatibility target. This directory records
Expand Down
101 changes: 101 additions & 0 deletions contracts/agents-api/list-query-semantics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# List query semantics — September 23, 2026

The fixed target remains openai-python 3.13.0, commit
`d7c41efee1b0802b79f3f88a678ef2052b06e9ce`, with `agents=v1` on beta resources.
This batch starts from Core main `c86b5bb` and addresses list order validation and
the error fields actually observed for those requests. It does not change page
limits, cursor lookup order, execution or native harness behavior.

## Official observations

Exactly 35 new read-only official GET requests were made, with no retries, resource
writes or model execution. Nested requests used random missing Session/Vault IDs;
top-level requests used missing cursors or a nonexistent Agent filter. Every
successful list was empty. Evidence, request IDs, fixed type copies and the full
matrix are retained under
`~/.parsar/remediation/20260923/error-query-survey/`. Earlier owned Session/Turn
observations are separately identified in that directory, not counted as new calls.

The nine sampled collections rejected explicit `order=`. The fixed enum permits
only `asc` or `desc`; omission and an explicitly empty string are different inputs.

| Measured request | Status | Error type | Code | Param |
| --- | --- | --- | --- | --- |
| Empty order on Agents, Sessions, Turns, Items, Templates, Vaults, Credentials | 400 | invalid_request_error | invalid_request_error | null |
| Empty order on Files | 400 | invalid_request_error | null | null |
| Empty order on Skills | 400 | invalid_request_error | invalid_value | order |
| Invalid status on Vaults/Credentials | 400 | invalid_request_error | invalid_request_error | null |

These are operation-specific observations. Do not apply the Skills code to all
validation errors or make every Files error share one parameter. Other endpoints
using the same order enum may share the parser, but were not independently probed
here. Authentication and ownership checks retain their existing boundaries.

The fixed Python SDK's query serializer drops empty string values. Consequently,
`list(order="")` does not send `order=` and follows omission/default behavior.
Explicit-empty rejection requires raw HTTP evidence; nonempty invalid SDK order
values exercise the rejected path normally. Do not alter Core or the SDK to hide
that request-serialization distinction.

## Deferred differences and uncertainty

- Query limits require separate qualification. Missing cursors or parents can mask
a later numeric validation error. A successful filtered-empty request does not
establish useful zero-sized pagination or an actual maximum page capacity.
- An owned official Item list accepted 101 although its pinned type documents
1–100; an owned Turn list rejected 101. Keep the fixed range until the conflict
is resolved explicitly. No general range change follows from this survey.
- Vault/Credential negative limits rejected on the official service, while the
pinned description broadly says values clamp to 1–100. Core's clamping policy
is unchanged in this batch.
- Files invalid purpose and missing cursor expose different `param` values;
purpose typing and cursor behavior need a separate bounded decision. The
verbose Files validation message and additional `detail` object are not a
reason to recreate an upstream validation framework.
- Two malformed Skills cursor observations returned 500, while a shaped missing
cursor returned 404. Retain the evidence; do not deliberately reproduce an
upstream failure or weaken safe missing-resource handling.
- Unknown/repeated query keys, whitespace cursors, numeric overflow, all status
combinations and concurrent-page mutation were not newly qualified.

Current documentation was consulted alongside the pin, including the
[Session list reference](https://developers.openai.com/api/reference/go/resources/beta/subresources/agents/subresources/sessions/methods/list)
and [Vault list reference](https://developers.openai.com/api/reference/typescript/resources/beta/subresources/agents/subresources/vaults/methods/list).
New documentation and sampled tolerance do not silently replace the fixed SDK.

## Acceptance boundary

Acceptance must exercise fixed-SDK and raw HTTP requests against the actual Core
service and a dedicated PostgreSQL database: rejected queries, omitted/valid order,
scoped history and pagination, authentication, tenant isolation and no mutation
from rejected GETs. Controlled tests support the same contract. This read-only
change requires no new native-model capability qualification; existing real-model
evidence retains its original scope. Record completed checks and independent review
before merging; neither a deserializable response nor a route inventory proves
complete compatibility.

## Completed acceptance

The nine-family fixed-SDK/raw-HTTP regression passed against actual Core HTTP,
PostgreSQL and Worker admission with dispatch paused. It checked 35 primary
rejections, nine SDK empty-query omission cases, successful ascending/descending
and default pagination, authentication and foreign-tenant masking. Resource
snapshots and the original three cancelled Turns/three Items remained unchanged.
The baseline failed at raw empty-order admission; the implementation passed.
This is resource/query acceptance, not native or model execution. Logs, exact
SDK serializer source and hashes are retained in the survey directory's
`ACCEPTANCE.md`; its owned database was removed.

Server `make -o check-web check` passed at `e4cb8a5`, including the dedicated
PostgreSQL regression, sqlc regeneration, service/adapter Go tests and builds,
Claude/MiniMax checks and Rust tests/format/Clippy. Web/client source and dependencies
are unchanged from PR #35: its 287 client tests, 583 Web tests and 76 browser cases
remain the applicable exact-source evidence; no new Web run is claimed. The
optional packaged MiniMax native-tools probe was skipped. This batch changes no
Runtime/provider/model behavior and does not requalify their combinations.

A fresh independent GPT-6 Astra high reviewer found no grounded in-scope findings
after inspecting the full diff and evidence; API tests and `git diff --check`
passed independently. Server logs are retained under
`~/.parsar/remediation/20260923/list-query-alignment/`. The remaining limits, cursor,
lookup and Files verbose error differences above are not declared compatible.
48 changes: 32 additions & 16 deletions contracts/agents-api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2050,7 +2050,8 @@ paths:
name: limit
type: integer
- default: desc
description: Creation order
description: Creation order; omit for descending, explicit empty values are
invalid
enum:
- asc
- desc
Expand Down Expand Up @@ -2373,7 +2374,8 @@ paths:
name: limit
type: integer
- default: desc
description: Case-sensitive path-component order
description: Case-sensitive path-component order; omit for descending, explicit
empty values are invalid
enum:
- asc
- desc
Expand Down Expand Up @@ -2509,7 +2511,8 @@ paths:
name: limit
type: integer
- default: desc
description: Creation order
description: Creation order; omit for descending, explicit empty values are
invalid
enum:
- asc
- desc
Expand Down Expand Up @@ -2772,7 +2775,8 @@ paths:
name: limit
type: integer
- default: desc
description: Creation order
description: Creation order; omit for descending, explicit empty values are
invalid
enum:
- asc
- desc
Expand Down Expand Up @@ -3133,7 +3137,8 @@ paths:
name: limit
type: integer
- default: desc
description: Publication order
description: Publication order; omit for descending, explicit empty values
are invalid
enum:
- asc
- desc
Expand Down Expand Up @@ -3497,7 +3502,8 @@ paths:
name: limit
type: integer
- default: desc
description: Creation order
description: Creation order; omit for descending, explicit empty values are
invalid
enum:
- asc
- desc
Expand Down Expand Up @@ -3559,7 +3565,8 @@ paths:
name: limit
type: integer
- default: desc
description: Resource order
description: Resource order; omit for descending, explicit empty values are
invalid
enum:
- asc
- desc
Expand Down Expand Up @@ -3683,7 +3690,8 @@ paths:
name: limit
type: integer
- default: desc
description: Resource order
description: Resource order; omit for descending, explicit empty values are
invalid
enum:
- asc
- desc
Expand Down Expand Up @@ -3754,7 +3762,8 @@ paths:
name: limit
type: integer
- default: desc
description: Creation order
description: Creation order; omit for descending, explicit empty values are
invalid
enum:
- asc
- desc
Expand Down Expand Up @@ -3888,7 +3897,8 @@ paths:
name: limit
type: integer
- default: desc
description: Resource order
description: Resource order; omit for descending, explicit empty values are
invalid
enum:
- asc
- desc
Expand Down Expand Up @@ -3955,7 +3965,8 @@ paths:
name: limit
type: integer
- default: desc
description: Creation order
description: Creation order; omit for descending, explicit empty values are
invalid
enum:
- asc
- desc
Expand Down Expand Up @@ -4056,7 +4067,8 @@ paths:
name: limit
type: integer
- default: desc
description: Creation order
description: Creation order; omit for descending, explicit empty values are
invalid
enum:
- asc
- desc
Expand Down Expand Up @@ -4296,7 +4308,8 @@ paths:
in: query
name: limit
type: integer
- description: Creation order
- description: Creation order; omit for descending, explicit empty values are
invalid
enum:
- asc
- desc
Expand Down Expand Up @@ -4452,7 +4465,8 @@ paths:
in: query
name: limit
type: integer
- description: Version order
- description: Version order; omit for descending, explicit empty values are
invalid
enum:
- asc
- desc
Expand Down Expand Up @@ -4601,7 +4615,8 @@ paths:
name: limit
type: integer
- default: desc
description: Creation order
description: Creation order; omit for descending, explicit empty values are
invalid
enum:
- asc
- desc
Expand Down Expand Up @@ -4827,7 +4842,8 @@ paths:
name: limit
type: integer
- default: desc
description: Creation order
description: Creation order; omit for descending, explicit empty values are
invalid
enum:
- asc
- desc
Expand Down
1 change: 1 addition & 0 deletions contracts/agents-api/operation-evidence.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Repository paths below are relative to the inspected worktree; private evidence
| E | `~/.parsar/remediation/20260922/official-semantics-alignment/error-surface-probe.json`: missing non-beta File/Skill observations only. Not successful-resource or full error-surface coverage. |
| C | `~/.parsar/remediation/20260922/official-semantics-alignment/live/acceptance-summary.json`, source `7c80d604ba47c578084ebc9fa99cff332bd5d5f2`. Seven resource/safety groups (DB), plus three real Turns per harness (Live): Codex/Claude Kimi K3; MiniMax M2.7. Successful runs: `live/resources/run-1790091139881592673`, `live/codex/run-1790091781322707360`, `live/claude_sdk/run-1790091781322554888`, `live/mcode/run-1790091781324544033`; each has `result.json` and `raw-evidence.json`, model runs also history/SSE evidence. Four network-interrupted attempts remain failures. No new native capability/OAuth refresh/E2B qualification. |
| N | `contracts/agents-api/official-semantics-alignment.md`, September 23 admission section; private `~/.parsar/remediation/20260923/session-admission-alignment/{official,live}/`: conditional create/update official probes plus exact-source `7ccc636` Core/daemon real none execution (six Turns), write rejection, local retry, metadata and isolation. Qualified idle hosted admission and Codex self-hosted admission are not new execution profiles. |
| Q | [List query semantics](list-query-semantics.md); private `~/.parsar/remediation/20260923/error-query-survey/REPORT.md` and `request-index.md`: 35 read-only official GETs, nine empty-order rejections and family-specific error fields. Missing-parent/cursor cases do not qualify later numeric bounds. No model execution or resource creation. Core acceptance is recorded in the linked batch document when complete. |
| A | `contracts/agents-api/official-semantics-alignment.md`: merged status/envelope/no-op/error/rejection changes and explicit remaining differences. `contracts/agents-api/README.md:63` supplies the current resource ledger; it is a coverage summary, not raw evidence. |
| T | `contracts/agents-api/execution-tools.md`: per-operation input, function, required-action, structured-output, discovery and policy matrix; evidence register M1/M2/F1/F2/F3/S1/S2/D1/P1/E1/E2 gives exact private run paths. These are profile-specific real acceptances. The older blanket OAuth rejection in this document is superseded by O. |
| D | `contracts/agents-api/README.md:115`, `contracts/agents-api/user-managed-runtime-v1.md`: recorded three-harness Docker MVP and separate user-managed Docker/E2B qualification. Historical `~/.parsar/remediation/20260920/three-harness-mvp/REPORT.md`, `acceptance-results.json` on zju_a100_2; prior Core-managed E2B qualification is retired-route evidence, not current enrollment qualification. |
Expand Down
2 changes: 1 addition & 1 deletion services/agents-api/internal/api/agents_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
// @Param OpenAI-Beta header string true "agents=v1"
// @Param after query string false "Last Agent ID from the previous page"
// @Param limit query int64 false "Maximum requested resources; pages contain at most 100" minimum(1)
// @Param order query string false "Creation order" Enums(asc,desc) default(desc)
// @Param order query string false "Creation order; omit for descending, explicit empty values are invalid" Enums(asc,desc) default(desc)
// @Success 200 {object} v1.SavedAgentList
// @Failure 400,401,404,500 {object} v1.ErrorResponse
// @Router /agents [get]
Expand Down
2 changes: 1 addition & 1 deletion services/agents-api/internal/api/credentials_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
// @Param vault_id path string true "Vault ID"
// @Param after query string false "Last Credential ID from the previous page"
// @Param limit query integer false "Requested page size, clamped to 1–100" default(20)
// @Param order query string false "Creation order" Enums(asc,desc) default(desc)
// @Param order query string false "Creation order; omit for descending, explicit empty values are invalid" Enums(asc,desc) default(desc)
// @Param status query string false "Scalar status filter" Enums(active,archived)
// @Param status[] query []string false "Array status filter; cannot be combined with status" collectionFormat(multi) Enums(active,archived)
// @Success 200 {object} v1.CredentialList
Expand Down
2 changes: 1 addition & 1 deletion services/agents-api/internal/api/environment_files.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func WithEnvironmentDirectoryReader(reader EnvironmentDirectoryReader) Option {
// @Param environment_id path string true "Environment ID"
// @Param path query string false "Absolute directory inside the Environment workspace"
// @Param limit query int false "Maximum file count; local default 20" minimum(1) maximum(100)
// @Param order query string false "Case-sensitive path-component order" Enums(asc,desc) default(desc)
// @Param order query string false "Case-sensitive path-component order; omit for descending, explicit empty values are invalid" Enums(asc,desc) default(desc)
// @Param page query string false "Opaque continuation token; keep path, order and limit unchanged"
// @Success 200 {object} v1.EnvironmentFileList
// @Failure 400,401,404,500,503 {object} v1.ErrorResponse
Expand Down
4 changes: 2 additions & 2 deletions services/agents-api/internal/api/environment_files_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func readEnvironmentFileQuery(w http.ResponseWriter, r *http.Request, environmen
return options, false
}
for key, values := range q {
if !slices.Contains([]string{"path", "limit", "order", "page"}, key) || len(values) != 1 || values[0] == "" {
if !slices.Contains([]string{"path", "limit", "order", "page"}, key) || len(values) != 1 || (key != "order" && values[0] == "") {
writeError(w, http.StatusBadRequest, "invalid_request", "Supported list parameters are path, limit, order and page, each supplied once with a nonempty value.")
return options, false
}
Expand All @@ -40,7 +40,7 @@ func readEnvironmentFileQuery(w http.ResponseWriter, r *http.Request, environmen
pageQuery[key] = values
}
}
page, ok := readPageQuery(w, pageQuery, true)
page, ok := readPageQuery(w, r, pageQuery, true)
if !ok {
return options, false
}
Expand Down
3 changes: 3 additions & 0 deletions services/agents-api/internal/api/environment_files_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ func TestEnvironmentFilesRejectsInvalidRequestsBeforeRead(t *testing.T) {
if w.Code != 400 || f.lookups != 1 || f.reads != 0 {
t.Fatal("invalid query reached runtime", w.Code, w.Body, f)
}
if query == "order=" || query == "order=ASC" {
assertListQueryError(t, w, "invalid_request_error", nil, "Failed to deserialize query string: order: unknown variant `"+strings.TrimPrefix(query, "order=")+"`, expected `asc` or `desc`")
}
})
}
}
Expand Down
2 changes: 1 addition & 1 deletion services/agents-api/internal/api/environment_templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func (h *Handler) deleteEnvironmentTemplate(w http.ResponseWriter, r *http.Reque
// @Param OpenAI-Beta header string true "agents=v1"
// @Param after query string false "Previous Template ID"
// @Param limit query integer false "Page size" default(20) minimum(1) maximum(100)
// @Param order query string false "Creation order" Enums(asc,desc) default(desc)
// @Param order query string false "Creation order; omit for descending, explicit empty values are invalid" Enums(asc,desc) default(desc)
// @Success 200 {object} v1.EnvironmentTemplateList
// @Failure 400,401,404,500 {object} v1.ErrorResponse
// @Router /agents/environments/templates [get]
Expand Down
Loading
Loading