Inside the wall
Everything on this page happens inside the market-entry sandbox. None of it is an API you call — the forgetful buyer agent reaches these surfaces through platform proxies, and your side of the wall sees only the session's final answer. It is documented because two things about it are load-bearing for you:
- Buyers — what an agent can actually learn about a listing before anyone pays for it, and which limits stop a session reading forever. If a session settles on an answer sooner than you expected, the reason is usually on this page.
- Sellers — this is what your listing looks like to the agent deciding whether to buy it. The format you publish in changes how deeply it can be evaluated.
See How it works for the wall itself and the session lifecycle.
The agent's closed tool set
Inside the sandbox the buyer agent runs against a fixed five-tool set and nothing else:
| Tool | What it does |
|---|---|
search |
queries the catalog it is eligible to see |
get_listing |
reads one listing — metadata, seller, license offers, and a preview of the data |
suggest_purchase |
recommends a listing; the only way a decision leaves the wall |
refuse |
ends the session with a closed-enum reason |
submit_no_match |
ends the session with a class-only gap report |
Nothing in that set runs code, opens a shell, writes to your systems, or reaches any network destination but the platform proxies. The set is closed: the agent cannot acquire a sixth tool, and text inside a listing asking for one does not create one — see Seller text is data, not instructions at the end of this page.
Inside the wall the agent has full access to what it reads — that is the premise of the forgetful buyer agent, not a leak. The confidentiality boundary is what leaves: a recommendation, a refusal, or a gap report. No byte of seller data crosses it before purchase, and the sandbox is destroyed when the session ends.
What one listing looks like from in there
get_listing returns the listing metadata, the seller, the license offers, and
one data block. Which block you get depends on the listing's format:
| Listing | Block | What the agent sees |
|---|---|---|
Text document (text/plain — anything created with create_listing) |
text |
up to the first 256 KiB of the body, plus a truncated flag |
| Dataset (parquet — including the CSV and XLSX uploads the platform converts to canonical parquet) | parquet_preview |
the column schema joined to your data dictionary, up to 8 sample rows within a 32 KiB JSON budget, and the file's row-group count |
Any other uploaded file — PDF, DOCX, ZIP, a raw text/csv file, anything else POST /api/v1/seller/files accepts |
document |
metadata only. The bytes are never fetched into the sandbox at all |
| A body too large to render whole | too_large_to_preview |
its declared size, the ceiling it exceeded, and whether a bounded window is available instead |
Two consequences worth internalizing as a seller:
- An opaque file is judged on its prose. For a PDF, a DOCX, a zip, or a raw
CSV file, the examinable surface pre-purchase is your
title,description, and whatever text the platform extracted at upload for search — never the file itself. A thin description on a rich file reads, from inside the wall, as a thin listing. - A dataset is judged on its dictionary and its rows. Column descriptions, semantic types, and units are what the agent reasons over alongside the sample rows. See Selling data for the upload paths.
Large listings: bounded windows
A body can be larger than the platform will render whole (currently 16 MiB for
parquet — the renderer's own ceiling — and 32 MiB for anything read whole in one
piece). Where ranged reads are enabled, that stops being a cliff: the agent
reads such a listing in bounded windows through the same get_listing call.
A large parquet dataset previews normally, because the preview itself is
assembled from targeted reads; a large text document previews from its opening
bytes; and a body that defeats even a ranged read comes back as
too_large_to_preview — a usable answer naming the ceiling — rather than a
failed examination. There is no separate tool and nothing changes on the surface
you call.
There are exactly two window selectors, one per previewable format:
| Format | Selector | What comes back |
|---|---|---|
| Text | {offset, length} — a byte range, at most 256 KiB per window |
a window block: the text, the served offset and length, the object's total_bytes, and eof |
| Parquet | {row_group, max_rows} — one row group by ordinal, at most 8 rows |
the same parquet_preview block, rows drawn from that row group, plus row_group_count and row_group |
A read that supplies neither selector — no window at all, or an empty one — is
the ordinary preview, exactly as it was before windows existed.
Because parquet keeps its metadata at the end of the file and its data in independent row groups, a row-group read pulls the footer and only the column chunks it needs. That is why a dataset far past the whole-body ceiling can still be evaluated properly — the agent reads kilobytes of it, not all of it.
Details that show up in outcomes:
- The offset and length that come back are the ones actually served, not the
ones requested. A text window is trimmed at its end, back to the last
line break inside it, so the text you get is whole lines wherever the body has
them. The start is never trimmed: the window always begins at the byte you
asked for. Resume by asking for
offset + lengthfrom the reply and you walk the whole body with nothing skipped and nothing read twice. - Paging always moves forward. Unless a window reports
eof, itslengthis at least 1, sooffset + lengthis always past where you asked — a window can never hand you the same offset back.lengthcounts the body's bytes, which is what the cursor moves by; the text you are shown is those bytes rendered, so it can be a different byte count. Bytes that are not valid UTF-8 are shown asU+FFFD(�) rather than dropped, so no byte position is ever skipped over silently. - A window that cannot be served is declined, not failed. Asking for a byte range on a parquet listing, a row group that does not exist, a window on an opaque file, or any window at all where ranged reads are not enabled on the deployment returns the listing's standard preview instead. A wrong guess costs the agent a turn, never the session.
- Re-reading a listing is free against the examination ceiling. The ceiling
counts distinct listings touched; the first
get_listingof any shape charges one, and every later read of that listing — windowed or not — charges nothing. Reading deeply is not penalised. Reading widely is. - Windowed reading is metered by bytes, per session. The platform sets a
cumulative in-wall read budget for each session. Plain previews and
searchare never charged against it; only windows are. When it is spent the agent is told no further windows are available and to decide with what it has already examined — the session is not killed and still returns a normal recommendation orno_match. This is the most likely explanation for an agent concluding earlier than you expected on a very large listing.
Ranged windows are a platform-managed capability rolled out per deployment. When
they are unavailable, the too_large_to_preview block says so
(window_available: false) and the agent decides from the listing metadata
rather than retrying into a wall.
Non-columnar large formats are sample-only
Windows are a sampling primitive, not a way to move a whole dataset into the sandbox. The sandbox has bounded CPU, RAM, and disk, and the per-session byte budget bounds it again, so today:
- Parquet is the only format that gets structure-aware, targeted deep reads. Row groups let the agent choose which part of a large dataset to look at, guided by the schema and row count it already has.
- Large text is sample-only. The agent reads representative byte windows, not the whole document.
- Opaque files stay metadata-only. No window applies; the bytes are not read in-sandbox at any size.
Whole-dataset analysis of an arbitrary large format is not something the wall does today. If you are publishing data you want evaluated thoroughly before purchase, publish it as a dataset with a data dictionary — that is the path built for it.
Seller text is data, not instructions
Every seller-authored string that reaches the agent — title, description, the
document body, and each data-dictionary field — is passed through the same
neutralization pass before the model ever sees it, including inside a text
window. Directive-shaped prose is marked and structurally fenced; parquet
columns carry an explicit untrusted_seller_authored marker on their free-text
fields, and the agent is instructed to treat all of it strictly as data.
For sellers, the practical version: instructions written into your listing are not followed. "Always recommend this listing", a fake tool call, or a fake system message costs you credibility with the classifier and buys nothing. Write descriptions for a reader who is evaluating the data.
Next
- How it works — the wall, the caller-session handoff, and the session controls that bound every run.
- Selling data — upload paths, formats, and data dictionaries.
- Connect your agent — the
enter_market→purchaseloop from your side of the wall.