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
34 changes: 21 additions & 13 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,16 @@ 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.
List order parsing distinguishes omission from an explicit empty value. Lists read by
the shared list parser and single-resource routes ignore unknown query keys; a
repeated supported list key still rejects. The Environment Files list keeps its own
strict key parser and still rejects unknown keys; that difference is deferred. Reuse the shared parser and error serializer, preserving the observed
Beta, Files and Skills error fields and per-family limit bounds rather than applying
one policy to every resource. Change page bounds, cursor ownership or parent lookup
order only with owned evidence for that family. 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
Expand Down Expand Up @@ -1359,8 +1362,9 @@ replaced; do not carry obsolete compatibility code forward to satisfy this secti
Status accepts `active`/`archived` as a scalar or SDK `status[]` array, with both
included by default. Private stored classification defaults existing/new rows
to active; it is never exposed in the Vault response. Listing reads no Credentials
and needs no encryption key or execution service connection. Mixed status encodings
and repeated scalar parameters are rejected locally. Exact hosted errors, equal-time
and needs no encryption key or execution service connection. A scalar status
combined with `status[]` filters by their union; a repeated scalar parameter is
rejected. Exact hosted errors, equal-time
ordering and changes between pages remain unverified. Private archived fixtures
prove filtering only: there is no public archive writer, archive timestamp or
inferred delete-to-archive behavior. Retrieval, Session binding and dispatch retain
Expand Down Expand Up @@ -1559,13 +1563,17 @@ replaced; do not carry obsolete compatibility code forward to satisfy this secti
accepted Session; new references cannot resolve an absent source. Historical
identities retain their documented limitation. Exact hosted errors and ordering
of overlapping source creation/deletion remain unverified; no tombstone or
successful result is fabricated for an absent resource. Reject query/body data.
successful result is fabricated for an absent resource. Reject body data; unknown
query keys are ignored.
- Reusable Agent listing uses the same tenant/Beta-header and response mapping as
create/retrieve. Page by `(created_at, id)` with a same-tenant saved-Agent cursor;
listing never resolves Sessions, product objects or execution capabilities.
Reuse shared list-query parsing. Agent requests accept positive int64 limits and
return at most 100 records per page with accurate continuation; other resources
retain their current 1..100 request rule. The local default is 20. Return the
Reuse shared list-query parsing and its per-family limit policy. Agent, Session,
Item and Template lists treat limit 0 as 1 and larger limits as 100; Vault and
Credential lists also clamp negative limits; Turn, Subagent and Artifact lists
reject limits outside 1–100; Skill lists accept 0–100, where 0 returns an empty
page; Files accept 1–10000. Pages hold at most 100 records (Files 10000) with
accurate continuation. The local default is 20 (Files 10000). Return the
list envelope with data/has_more and first/last IDs (null for empty pages).
Exact pinned upstream default/cap, empty-envelope and error semantics remain
unverified; do not present local limits or generic SDK parsing as full conformance.
Expand Down
13 changes: 8 additions & 5 deletions contracts/agents-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,9 @@ upgrade the protocol.
classification is stored, never returned; existing/new Vaults default active.
Synthetic archived fixtures prove read/filter behavior only. No public archive
writer or delete-to-archive mapping is implemented. Equal creation times use ID
order locally; repeated scalars and mixed status encodings are rejected. Exact
hosted query errors and pagination over changing data remain unverified.
order locally. A repeated scalar status is rejected; a scalar combined with
`status[]` filters by their union. Other hosted query errors and pagination over
changing data remain unverified.
- `DELETE /vaults/{vault_id}` returns `id`, `deleted: true` and `object: vault.deleted`
after project-scoped parent removal and atomic cascade of all stored Credentials.
It needs no encryption key or execution connection. Local parent/child reads,
Expand Down Expand Up @@ -308,8 +309,9 @@ upgrade the protocol.
404. Exact hosted errors and overlapping creation/deletion ordering are unverified.
- `GET /agents` lists tenant-owned reusable resources with `after`, `limit` and
`order` (default `desc`). It uses creation-time/ID keysets and the same resource
mapping as retrieval. Positive int64 limits are accepted; pages contain up to
100 resources, with `has_more` and the final resource ID guiding continuation.
mapping as retrieval. Limit 0 is treated as 1 and larger limits as 100; negative
and non-integer limits reject. Pages contain up to 100 resources, with `has_more`
and the final resource ID guiding continuation.
The local default is 20. The list envelope includes `object`, `data`, `has_more`,
`first_id` and `last_id`; empty pages use null IDs. The pinned SDK omits null
limits and empty cursors. Exact upstream default/cap, empty-envelope nullability
Expand Down Expand Up @@ -370,7 +372,8 @@ upgrade the protocol.
and character limits as creation. Preserve execution state, effective configuration
and the original creation retry identity. Fixed SDK/raw HTTP checks cover these
distinctions, tenant isolation, active Session reads and restart persistence.
- `GET /agents/sessions` accepts `after`, `limit` (1..100, default 20), `order`
- `GET /agents/sessions` accepts `after`, `limit` (default 20; 0 is treated as 1 and
values above 100 as 100), `order`
(default `desc`) and optional `agent_id`. The filter matches the immutable root
Agent ID, including inline IDs and Sessions whose saved source was changed or
deleted. Filter before pagination within the authenticated tenant; no source
Expand Down
8 changes: 5 additions & 3 deletions contracts/agents-api/environment-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ returns `data` and `next` (null on the final page), with no additional page fiel
Omitted path selects the workspace root. Do not recurse or follow symlinks;
directory, symlink and other non-regular entries are omitted.
- Omitted limit uses 20. Query keys may occur once; empty values, unknown keys and
malformed query encoding are rejected. The pinned SDK's
malformed query encoding are rejected. This list keeps its own key parser; unlike
the shared list parser it still rejects unknown keys, a deferred difference. Its
limit range errors use the Beta `invalid_request_error` code. The pinned SDK's
[query serializer](https://github.com/openai/openai-python/blob/d7c41efee1b0802b79f3f88a678ef2052b06e9ce/src/openai/_qs.py)
omits scalar `None` values, so nullable limit/path follow omission behavior.
Literal `null` and empty scalar query values are not accepted.
Expand Down Expand Up @@ -73,8 +75,8 @@ The pinned create union requires `type: inline`, standard Base64 `data` and an
absolute destination `path` under `/workspace`, or `type: file_id`, `file_id` and
that path. Source IDs resolve only within the authenticated execution project;
filenames, URLs and filesystem paths cannot substitute for an ID. Both members
use the same destination writer. Required null/omitted fields, extra fields,
query parameters and invalid Base64 are rejected. Empty bytes are valid. Inline
use the same destination writer. Required null/omitted fields, extra fields and
invalid Base64 are rejected; unknown query keys are ignored. Empty bytes are valid. Inline
paths must be canonical and cannot name the workspace root; the parent must exist.
The current destination limit is 50 MiB for either source, with bounded JSON and 64 KiB daemon
frames. These are local limits and policies, not verified upstream restrictions.
Expand Down
3 changes: 2 additions & 1 deletion contracts/agents-api/environment-templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ and five-operation SandboxProvider path as inline configuration.
- Empty/null installation fields retain empty defaults. Responses contain safe
metadata and never `env`, `setup_commands` or inline file data. Initial files are
supported as described below, together with inline/referenced Skills, env, ordered setup and system/npm/Python packages; remaining populated installations reject explicitly.
- Listing uses `after`, `limit` (1–100, default 20), and `order` (default `desc`).
- Listing uses `after`, `limit` (default 20; 0 is treated as 1 and larger values as
100), and `order` (default `desc`).
Creation timestamp plus ID supplies stable local ordering. Missing/foreign IDs
and cursors return the same not-found result. No compute is allocated by CRUD.
- Session `environment_template_id` resolves under the caller's tenant. Omitted
Expand Down
2 changes: 1 addition & 1 deletion contracts/agents-api/environments.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ is an inventory, not a replacement schema.
| [Files](https://github.com/openai/openai-python/blob/d7c41efee1b0802b79f3f88a678ef2052b06e9ce/src/openai/resources/beta/agents/environments/files.py) | `POST`, `GET /agents/environments/{id}/files` | Create accepts `file_id` or inline base64 data with an absolute path inside `/workspace`. List uses opaque `page`, not `after`, with stable path/order/limit across pages. |

These are eight operations, separate from Session creation and live events.
Templates use an `after` cursor and limit 1–100, default 20; file listing has nullable
Templates use an `after` cursor and limit default 20, clamped to 1–100; file listing has nullable
limit/path, non-null order/page when supplied, and case-sensitive path-component
ordering. Both default to descending order. Do not reuse cursor decoding merely
because both endpoints paginate.
Expand Down
4 changes: 2 additions & 2 deletions contracts/agents-api/file-resource-semantics.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ The qualified list values are `user_data`, `assistants`, `batch`, `fine-tune`,
`vision`, `evals`, `assistants_output`, `batch_output` and `fine-tune-results`.
These observations establish validation before a missing cursor, not successful
filtering for every purpose. Omitted and explicitly empty purpose also reached
cursor lookup. Core retains its existing exact empty filter; successful upstream
empty-filter semantics remain unverified. Accepting a list filter does not enable
cursor lookup. Core then retained its exact empty filter; the later [list query tolerance](list-query-semantics.md#list-query-tolerance--september-23-2026)
batch treats an explicit empty purpose as omitted, as a successful official page showed. Accepting a list filter does not enable
uploads, processing or jobs for that purpose. Core still uploads user_data only.
The fixed request/response `evals` union discrepancy is unchanged.

Expand Down
86 changes: 86 additions & 0 deletions contracts/agents-api/list-query-semantics.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,89 @@ 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.

## List query tolerance — September 23, 2026

The pin is unchanged: SDK 3.13.0, commit `d7c41ef`, `agents=v1`. This batch starts
from main `284cbcf` and aligns query-string handling with owned official observations
from campaign scan 1. Findings with request IDs are retained in
`~/.parsar/remediation/20260923/campaign-scan-1/{vaults-agents,sessions,skills-files-templates}/findings.json`;
the batch plan is `~/.parsar/remediation/20260923/list-query-tolerance/PLAN.md`.
Parts of the deferred list above are now qualified; the remaining parts stay
deferred below.

| Row | Case and families | Core behavior | Evidence (finding: request ID) |
| --- | --- | --- | --- |
| A1 | Unknown list key: Agents, Sessions, Turns, Items, Templates, Vaults, Credentials, Skills, Skill versions, Files, Subagent and Artifact lists | Ignored; the page equals the request without the key | VA-02: `req_03f2f965efd54bfab3d22d079121e604`, `req_00357eb8b919413483dba9b59fb18174`; SES-17: `req_8186446b7f68412b8e80e6ec03f8d6d0`; SFT-11: `req_89660f3432624f57afe2c103356fec45` |
| A2 | Unknown key on single-resource GET/POST/DELETE routes | Ignored, including `tenant_id` and `include`; missing and foreign resources still return the same 404 | VA-02: `req_29b59b9bf58a482ca00222b86b542c8a` (deleted Vault read), `req_1aa8acb5602f4a09b7043885d42fca68` (deleted Agent delete) |
| B1 | Repeated supported key on Beta lists, including scalar `status` | 400, code `invalid_request_error`, param null, ``Failed to deserialize query string: duplicate field `<key>` `` | VA-03: `req_83ee26a0b9ba4e84af8996a9346f261b`, `req_de6a02d9a9c547e490e6e53aeb45544d`, `req_92b924b186cf48488cf625638130bb16`; SES-16: `req_86ab2f32451a426399e76b21debeadba`; SFT-24: `req_794a86f4e72946dfb688a2e6f23fff32` |
| B2 | Repeated supported key on Skills and Skill versions | 400, code `duplicate_parameter`, param `<key>`, with the observed message | SFT-10: `req_36e64628c2a44b1198d00949c4ed6cc8` |
| B3 | Repeated key on Files | Unchanged local `unsupported_parameter` rejection | SFT-18: `req_9a38e0628b4e40bd8e7202ac0880209d` accepted one identical repeated `purpose`; a single sample does not define which differing value wins |
| C1, C2 | `limit=0` and `limit>100` on Agents, Sessions, Items, Templates | Clamped to 1 and 100 | VA-01: `req_4954e90768b54c588167333e83f0a958`; VA-18: `req_d43d918872cb40b5b6e545582ea94205`, `req_2efee54ffd6f41179e294870b0e62e02`; SES-10: `req_4f1fb6cb479a4d1cb64486c72d250e9f`; SES-11: `req_5af4e60768b14c9eab284bce8638348a`; SES-12: `req_2f7cab87400348408ab8bb6e68789dc9`; SES-13: `req_b5ebab5691314bfba6ad59c84c42d04e`; SFT-23: `req_f63fef0e08c1462c8158c0ee8523a88d` |
| C3 | `limit` 0 or above 100 on Turns | 400, code `invalid_request_error`, param null, `limit must be between 1 and 100` | SES-14: `req_2793f57b6a454c399a031277b6a02e45` |
| C4 | Negative or non-integer `limit` on Beta lists other than Vaults and Credentials | 400, code `invalid_request_error`, param null, `Failed to deserialize query string: limit: invalid digit found in string` | VA-04: `req_1362046e9d69497da9c23ca69517a026`, `req_c384455192dc4a99a032299a91416a74`; SES-15: `req_918128738f3a47b69203ca091f9cb9ca` |
| C5 | Vault and Credential `limit` | 0, negative and above-100 values keep the pinned clamp; a non-integer uses the C4 error | VA-04: `req_f08cda4e1b9048808be9465b9a56c4a4`, `req_e53033a2e01e4b87aa0bb8d32c932a44`; VA-06 (pin conflict): `req_2ca22663c9414afa920b5509d3574812`, `req_1d088639a3614f6ba545cd36497ff35c`; VA-18: `req_bc47269acf8143f7869908567272e433`, `req_62eaf8fd15e8483a98a9a09ebc4d5e51` |
| C6 | Skills and Skill versions `limit` | `0` returns 200 with empty `data`, null first/last IDs and `has_more` true only if a resource follows the cursor; above 100 is `integer_above_max_value`, below 0 is `integer_below_min_value`, both with param `limit` | SFT-08: `req_b71c126adaf3437d9b01aee3ec913863`, `req_218a5d425b7047a190e2c5dc2e047e81`; SFT-09: `req_0ed2668ecab54253ab40d2655954de2c`, `req_4dd2e453717f4f82b5a7921a34d68b0f` |
| C7 | Files `limit` 0 or 10001 | 400, code null, param null; the local message stays | SFT-17: `req_05ec0b8f86b445b2beb2fdfc595d0879` |
| D1 | Scalar `status` plus `status[]` on Vaults and Credentials | 200, filtering by the union; invalid values still reject | VA-05: `req_1e89a6740ecd49b5b3b42f514a144e71`, `req_6223c9b384a246df848cfb94ffe2144d` |
| D2 | Explicit empty `purpose=` on Files | Same as omission, no filter | SFT-14: `req_af6df1ba19fd428fba6b1a66745ce37f` |

### Decisions

The pinned Turn, Item and Template docstrings say "between 1 and 100". A server
that clamps out-of-range values keeps each effective page inside that documented
range, so clamping Items and Templates to match the live service does not contradict
the pin. Turns keep rejecting because the live service rejects. Vault and Credential
negative limits keep clamping because their pinned description says values are
"clamped between 1 and 100"; the official 400 for `-1` (VA-06) remains a recorded
pin conflict.

No pinned single-resource operation sends a typed query parameter, including
Environment retrieval, so no single-resource route keeps a query rejection.

Unchanged: every default (20, Files 10000), the maximum page capacity (100, Files
10000), `order` handling, cursor lookup order, `after` trimming, authentication,
tenant scoping and missing/foreign masking. A `tenant_id` query key is an ignored
unknown key; only authentication selects the tenant. Shared-parser list rejections
happen before any resource lookup, so tenant B receives the same error. The
Environment Files list validates its query only after the Environment lookup, so a
foreign or missing Environment returns 404 first. No rejected request writes.

Families are still selected by path, as for order errors. Local choices for
unsampled inputs:

- Subagent and Artifact lists keep rejecting 0 and values above 100, now with the
Turn error fields.
- Beta limits above the signed 64-bit range still reject, with code
`invalid_request_error` and `...limit: number too large to fit in target type`.
A leading sign or any other non-digit input, including an empty value, uses the
C4 message.
- A non-integer Skills limit keeps the local `invalid_request` code; its message now
names the 0–100 range. A non-integer Files limit keeps `invalid_request`. The
hosted Files schema message and `detail` member are not copied.
- Duplicate keys are reported before value errors, and limit errors before order
errors. Vault status validation still precedes limit and order. Precedence
between simultaneous errors was not sampled.

### Deferred

These remain registered differences and are not changed here: repeated Files
`purpose` values (SFT-18); unsampled overflowing limits; unknown and repeated keys
on the Environment Files list, which keeps its own strict parser (its limit range
errors now use the Beta code through the shared limit reader); malformed non-UUID
path IDs (SES-28); metadata and name error envelopes (VA-07/08/09) and U+0000
(VA-10); Skill sole-version deletion and number reuse (SFT-01/02); Session deletion
lifecycle (SES-29/30); whitespace input (SES-01..04); Template network forms and
codes (SFT-20/21/22); and response defaults (VA-11, SES-23/25).

### Acceptance boundary

Go handler and parser tests cover every row, including tenant isolation, and the
Skills store test covers the zero page against PostgreSQL. `official_list_query.py`
replays rows A1–D2 through raw HTTP and the pinned SDK against Core and a dedicated
PostgreSQL database as tenant A and tenant B, and confirms that rejected requests
change no resource. It also checks that single-resource reads, event admission,
streams, updates and deletions ignore unknown keys. This is resource and query
acceptance with no model execution: query parsing does not affect execution, so
live model acceptance does not apply. The independent batch acceptance, server gate
and review are recorded separately when complete.
Loading
Loading