open-standards/wai/wai-rs/include/wai.h
Transaction Science 2060e7de7a neural: the binding check reads the descriptor, the C ABI reports the path, and CI runs the exact decoder
check_reconstruction_binding compared only the hash, so a binding of another
decoderId, format or size than the exact decoder computes was reported as
Differs. reconstruction-binding §2 forbids reporting a binding as failed when
the verifier decoded some other way than its descriptor says. Such a binding
is now BindingCheck::OtherReconstruction, with the path that ran; for the
exact decoder that is any decoderId but 2.

wai_neural_decode_ex dropped the path and the capability, so a native sink
could not state its decoder entry's variant. wai_decoded_t gains `path`
(WAI_DECODE_PATH_SOLE, _EXACT or _FLOAT) and `fallback`, 1 when a WAI1
envelope decoded through its fallback. include/wai.h is regenerated.

The neural gates counted the two JPEG-AI cases' skips as passes, so CI ran
only the one-path case. That step now selects its two committed-input cases by
name, one of them a binding over int_mlicpp checked under its descriptor. A new
job in the 24.04 image fetches the pinned jpegai/v1 bundle and runs the exact
decoder's case with WAI_REQUIRE_SOTA_VECTORS=1, requiring it by name and
refusing a skip. The float decode needs the reference-software assets, which
no job holds, so its case runs locally only; the test header and
determinism-tiers §5 say so. The C ABI step runs the path and fallback test.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-04 12:29:01 -05:00

1344 lines
44 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* WAI — Web AI media transport + execution.
*
* Auto-generated by cbindgen from src/ffi.rs. DO NOT EDIT — regenerate
* by rebuilding `wai-rs` (the build.rs runs cbindgen) or by running
* cbindgen --config cbindgen.toml --crate wai --output include/wai.h
*
* SDK contract:
* - Every `wai_*` function returns a `wai_status_t` (typedef int).
* 0 = ok; non-zero = see WAI_ERR_* below + wai_last_error().
* - Any `WaiBuffer` written into an out parameter MUST be freed via
* `wai_buffer_free`. Passing a zero-cap buffer to free is safe.
* - `wai_last_error()` returns a NUL-terminated UTF-8 string that is
* valid until the next wai_* call on the same thread.
*
* Build the library:
* cargo build --release # produces libwai.{so,dylib,a}
* Link with:
* gcc your.c -lwai # static or dynamic per linker
*/
#ifndef WAI_H
#define WAI_H
#pragma once
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
/**
* The most samples a reader must accept from one audio payload (SPEC §2, *Reader
* limits*), counting every channel: 2^27, 46 minutes of one channel at 48 kHz. Decoded
* to `f32` it is 512 MiB. Longer audio is carried as more than one object.
*/
#define AUDIO_DECODED_MAX_SAMPLES (1 << 27)
/**
* The widest and the tallest picture a reader must accept (SPEC §2, *Reader limits*):
* 65 536 pixels, the largest side an AV1 sequence header can declare.
*/
#define IMAGE_MAX_SIDE (1 << 16)
/**
* The most pixels a reader must accept in one picture (SPEC §2, *Reader limits*):
* 2^27, a 16 384 × 8 192 picture. Decoded to 8-bit RGB it is 384 MiB.
*/
#define IMAGE_MAX_PIXELS (1 << 27)
/**
* The most bytes a `wai.text.zstd` or `wai.text.xz` payload may decode to that a reader
* must accept (SPEC §2, *Reader limits*): 2^27. The decoders here write no more than
* this, whatever the payload asks for: one that decodes to more is refused
* (`text_decoded_too_long`) when its output would pass the limit, so the output buffer
* never holds more. The reference writers refuse to encode more.
*/
#define TEXT_DECODED_MAX_LEN (1 << 27)
/**
* The base-2 logarithm of [`TEXT_WINDOW_MAX_LEN`].
*/
#define TEXT_WINDOW_MAX_LOG 27
/**
* The most history a `wai.text.zstd` or `wai.text.xz` stream may ask its decoder to
* keep that a reader must accept (SPEC §2, *Reader limits*): 2^27 bytes, as the zstd
* frame's window size or the LZMA2 dictionary size. A stream that declares more is
* refused (`text_window_too_large`) from the declaration, before the decoder allocates
* it. Together with [`TEXT_DECODED_MAX_LEN`] it bounds the memory a decode takes: the
* length limit bounds the output, and this bounds what the decoder holds beside it.
*/
#define TEXT_WINDOW_MAX_LEN (1 << TEXT_WINDOW_MAX_LOG)
/**
* The most temporal units a reader must accept in one AV1 payload (SPEC §2, *Reader
* limits*): 2^20, 4.9 hours at 60 frames a second. Each frame is held to the picture
* limits of [`crate::codecs::image::check_dimensions`].
*/
#define VIDEO_MAX_TEMPORAL_UNITS (1 << 20)
/**
* What the frames [`av1_decode`] returns may take together: 4 GiB of RGB. A payload
* within the reader limits can declare far more (2^20 frames of 2^27 pixels), and the
* whole-output entry points keep every frame at once, so they refuse one past their
* budget (`video_decoded_too_large`) from its header, before they decode.
* [`av1_decode_each`] keeps one frame at a time and decodes any payload within the
* reader limits.
*/
#define AV1_DECODE_DEFAULT_MAX_LEN 4294967296
/**
* The longest manifest, in bytes, a reader must accept (SPEC §2, *Reader limits*):
* 2^27 (128 MiB). It is sized to the largest manifest a conforming layer has: a `prev`
* (staged-delivery §3) that names a different producer for each of the 2^20 units a
* `WIR1` layer may cover (staged-delivery Appendix A.3, `n_units ≤ 2^20`), about 90
* bytes a run. The reference readers refuse a longer one before they read it, and the
* reference writers refuse to write one, so `man_len` never asks a reader to read
* more. It bounds the bytes read; [`MANIFEST_MAX_VALUES`] bounds what a parse builds
* from them. The manifest's nesting has its own limit: the JSON reader refuses 128
* nested arrays and objects and takes 127 ([`check_manifest_text`]).
*/
#define MANIFEST_MAX_LEN (1 << 27)
/**
* The most JSON values a manifest may hold that a reader must accept (SPEC §2, *Reader
* limits*): 2^22, counting the manifest object and every value nested in it, at any
* depth; a member's name is not a value. It is sized to the same layer as
* [`MANIFEST_MAX_LEN`]: a `prev` that names a different producer for each of 2^20 units
* is three values a run (the run, its `producer` and its `count`), 3·2^20 and a few more
* in all. The reference readers count a manifest's values before they parse it
* ([`check_manifest_text`]) and refuse it as soon as the count passes the limit
* (`manifest_too_many_values`), so the JSON tree a parse builds holds at most this many
* values, whatever the manifest's length.
*/
#define MANIFEST_MAX_VALUES (1 << 22)
/**
* The most samples, counting every channel, a reader must be willing to render from
* one object: 2^27, the audio limit of SPEC §2 (46 minutes of one channel at 48 kHz).
*/
#define RENDER_MAX_SAMPLES (1 << 27)
/**
* The most frames a reader must be willing to render from one object: 2^20, the
* video limit of SPEC §2 (4.9 hours at 60 frames a second).
*/
#define RENDER_MAX_FRAMES (1 << 20)
#define WAI_OK 0
#define WAI_ERR_INVALID_ARG 1
#define WAI_ERR_CODEC 2
#define WAI_ERR_CONTAINER 3
#define WAI_ERR_PANIC 4
/**
* A pin was refused (SPEC §3.1); `wai_last_error` starts with the reason.
*/
#define WAI_ERR_PRIOR 5
/**
* `intent = replicate` is not sound for the capability decoded through (SPEC §7).
*/
#define WAI_ERR_UNSOUND_REPLICATE 6
/**
* No rendition of a `WAI2` envelope can be picked (SPEC §7.1).
*/
#define WAI_ERR_NO_RENDITION 7
/**
* The budget a process starts with: 256 MiB. A set holds its weights as `i64` once
* lowered, four times their bytes in a `WHM1` file, so this keeps a set of about
* 60 MB of `WHM1` networks with room beside it for small ones.
*/
#define LoadedSets_DEFAULT_BUDGET (256 << 20)
/**
* What an entry is counted for beyond its set: its share of the store's two indexes
* (by key, and by last use). It is more than either index's node for one entry, so
* the count is never under what the store holds.
*/
#define LoadedSets_INDEX_BYTES_PER_ENTRY 4096
/**
* Probability output scale of [`softmax`]: results are at `2^PROB_FRAC`
* (they sum to ~`2^PROB_FRAC`).
*/
#define PROB_FRAC 16
/**
* Fractional bits of the Q16 fixed-point format.
*/
#define F 16
/**
* 1.0 in Q16.
*/
#define S (1 << F)
/**
* Number of action planes appended to the latent for the transition (dx, dy, btn).
*/
#define A 3
#define MARKER_SOC 65408
#define MARKER_EOC 65409
#define MARKER_PIH 65410
#define MARKER_TON 65411
#define MARKER_RDI 65412
#define MARKER_SOZ 65416
#define MARKER_SORP 65417
#define MARKER_SORS 65418
#define MARKER_SOQ 65419
#define MARKER_UDI 65420
/**
* The media kind of a [`WaiDecoded`].
*/
#define WAI_DECODED_AUDIO 1
/**
* The media kind of a [`WaiDecoded`].
*/
#define WAI_DECODED_IMAGE 2
/**
* The media kind of a [`WaiDecoded`].
*/
#define WAI_DECODED_VIDEO 3
/**
* `wai_neural_decode_ex` flag: apply SPEC §7's replicate rule (strict).
*/
#define WAI_DECODE_STRICT 1
/**
* The decode path of a [`WaiDecoded`]: the capability has one decode path
* (`neural::DecodePath::Sole`). A session claim's decoder entry states `variant` `null`.
*/
#define WAI_DECODE_PATH_SOLE 1
/**
* The decode path of a [`WaiDecoded`]: `wai.image.jpegai`'s exact decoder
* (`neural::DecodePath::Exact`). A session claim's decoder entry states `variant` `exact`.
*/
#define WAI_DECODE_PATH_EXACT 2
/**
* The decode path of a [`WaiDecoded`]: `wai.image.jpegai`'s float decode
* (`neural::DecodePath::Float`). A session claim's decoder entry states `variant` `float`.
*/
#define WAI_DECODE_PATH_FLOAT 3
#define SECTION_CONTRACT 1
#define SECTION_GRAPH 2
#define SECTION_ASSETS 3
#define SECTION_OPLOG 4
#define SECTION_SEAL 5
/**
* Payload = a record body (`n_cells u16 | cells…`). Target MUST
* equal `mint_node_id(actor, lamport)`. Resolution: LWW.
*/
#define CREATE 1
/**
* `pos[3] | vel[3] | scalar` (7 × i64). Target MUST equal
* `mint_node_id(actor, lamport)`. Resolution: LWW.
*/
#define CREATE 1
/**
* `pos[3] | vel[3] | radius | restitution` (8 × i64). Target MUST
* equal `mint_node_id(actor, lamport)`. Resolution: LWW.
*/
#define CREATE 1
/**
* `parent[16] | translation[3] | rotation[4] | scale[3]`
* (16 + 10×`i64` Fx = 96 bytes). Target MUST equal
* `mint_node_id(actor, lamport)`. `parent` is another bone's node
* id, or all-zero for a root.
*/
#define CREATE 1
/**
* Empty payload. Resolution: LWW.
*/
#define DELETE 2
/**
* Empty payload. Resolution: LWW.
*/
#define DELETE 2
/**
* Empty payload. Resolution: LWW.
*/
#define DELETE 2
/**
* Empty payload — remove the bone.
*/
#define DELETE 2
/**
* Empty payload; removes a particle or member. LWW.
*/
#define DELETE 2
/**
* `field_idx u16 | cell(tag u8 | value)` — replace one cell.
* Resolution: LWW.
*/
#define SET_CELL 16
/**
* `field_idx u16 | i64` — add to an `Int` cell (saturating).
* Resolution: SUM.
*/
#define ADD_INT 17
/**
* `field_idx u16 | i64` (Fx bits) — add to a `Fixed` cell
* (saturating). Resolution: SUM.
*/
#define ADD_FIXED 18
#define Fx_FRAC_BITS 32
/**
* `scalar` (1 × i64). Resolution: LWW.
*/
#define SET_SCALAR 3
/**
* `dv[3]` (3 × i64) added to velocity. Resolution: SUM — two
* actors shoving the same node both act; neither is discarded.
*/
#define IMPULSE 4
/**
* `dv[3]` (3 × i64) added to velocity. Resolution: SUM.
*/
#define IMPULSE 4
/**
* `dv[3]` (3 × i64) added to a particle's velocity. SUM.
*/
#define IMPULSE 4
/**
* `pos[3]` (3 × i64). Resolution: LWW.
*/
#define SET_POS 5
/**
* `pos[3]` (3 × i64). Resolution: LWW.
*/
#define SET_POS 5
/**
* `pos[3]` (3 × i64) on a particle. LWW.
*/
#define SET_POS 5
/**
* `rotation[4]` (4×`i64` Fx quaternion x,y,z,w) — the animation
* driver: set a joint's local rotation.
*/
#define SET_ROTATION 16
/**
* `translation[3]` (3×`i64` Fx).
*/
#define SET_TRANSLATION 17
/**
* `scale[3]` (3×`i64` Fx).
*/
#define SET_SCALE 18
/**
* Create a particle: `pos[3] | vel[3] | inv_mass` (7 × i64).
* `inv_mass == 0` is an anchor (infinite mass — foundations).
* Target MUST equal `mint_node_id(actor, lamport)`. LWW.
*/
#define CREATE_PARTICLE 1
/**
* Create a member between two particles:
* `node_a (16 B) | node_b (16 B) | yield_strain (i64)`.
* Rest length is measured from the endpoints' current positions
* at apply time (weld what's there — deterministic, since apply
* order is canonical). Target MUST be minted; endpoints missing
* or coincident → deterministic no-op. LWW.
*/
#define CREATE_MEMBER 16
/**
* Fixed PCM window per reconstruction block (samples). The final block may
* be short; every block carries its index, so the partition is canonical.
*/
#define SEGMENT_SAMPLES 4096
#define SAW 0
#define SQUARE 1
#define TRIANGLE 2
#define PULSE25 3
/**
* The standard uncertainty, in microjoules, that sealing an estimate as a
* whole number of microjoules adds (`extensions/energy-measurement.md` §2.3,
* `u_res`). `joules_micro` is an integer, so a figure rounded to the nearest
* microjoule lies within ±0.5 µJ of the estimate it came from. With only that
* limit known the error is taken as rectangular (GUM F.2.2.1): `0.5/√3` µJ.
*
* It is the same in microjoules whatever the figure, so relative to the
* figure it is large when the figure is small: 29 % of 1 µJ, 2.9 % of 10 µJ.
*/
#define RESOLUTION_UNCERTAINTY_UJ 0.2886751345948129
/**
* The standard uncertainty, in microjoules, of the difference of two readings
* of a register that counts whole microjoules. Each reading stands for an
* energy up to one step away from it; two such offsets, each rectangular over
* one step, differ by a triangular error over (−1, +1) µJ (GUM 4.3.9):
* `1/√6` µJ. This is the resolution of a figure read as a counter delta.
*/
#define REGISTER_DELTA_UNCERTAINTY_UJ 0.4082482904638631
/**
* The least `joules_micro × relative_ppm` a declaration may have (§2.3). A
* declared relative uncertainty `ppm` on a figure of `F` µJ is an absolute
* standard uncertainty of `F · ppm / 10⁶` µJ, which must be at least the
* least resolution a whole-microjoule figure carries,
* [`RESOLUTION_UNCERTAINTY_UJ`]. That is `F · ppm ≥ 288 675.13…`, and since
* `F · ppm` is an integer, `≥ 288 676`. A figure read as a register delta
* carries more, [`REGISTER_DELTA_UNCERTAINTY_UJ`], which this floor does not
* check.
*
* It is checkable from the receipt alone, in integers, so every verifier
* reaches the same verdict.
*/
#define RESOLUTION_FLOOR_UJ_PPM 288676
/**
* The most chaining values a proof may carry.
*/
#define HeadProof_MAX_CV 64
/**
* The fixed part of the file: magic, cid, `envelope_len`, `covered_len`, `n_cv`.
*/
#define HeadProof_FIXED_LEN 53
/**
* The bytes every walk of a stream sees, and every probe (§3.2).
*/
#define HEAD (1 << 20)
/**
* The bytes the measures and the search for embedded signatures see (§3.2).
*/
#define SCAN (16 << 20)
/**
* The structures one walk reads before it stops with `limit` (§3.3).
*/
#define MAX_STEPS 4096
/**
* The tracks one candidate reports (§3.3).
*/
#define MAX_TRACKS 64
/**
* The evidence one candidate reports (§3.3).
*/
#define MAX_EVIDENCE 8
/**
* The embedded signatures reported (§7).
*/
#define MAX_EMBEDDED 32
/**
* The longest string read from a file that a result holds (§3.4).
*/
#define MAX_STRING 64
/**
* The bytes the search for a repeat sees.
*/
#define PERIOD_SAMPLE (256 << 10)
/**
* The longest repeat searched for.
*/
#define PERIOD_MAX_LAG 4096
/**
* The window whose values are tested for a uniform spread.
*/
#define WINDOW 4096
/**
* A 4096-byte window is called uniform when the sum of its counts squared is at most this: its
* chi-square against a uniform spread is then at most 310, the 99th percentile for 255 degrees
* of freedom (§8.2).
*/
#define UNIFORM_SUM 70496
/**
* The z a lag must reach (§8.3).
*/
#define PERIOD_Z 8
/**
* The lags reported.
*/
#define MAX_PERIODS 8
/**
* An input that does not read: a configuration, an observation, an energy entry, an event
* (native-sink §9). `wai_last_error` starts with the reason.
*/
#define WAI_ERR_SINK_INPUT 8
/**
* A call on a session that has ended (native-sink §9).
*/
#define WAI_ERR_SINK_ENDED 9
/**
* The ABI's version: a host checks it before it opens a session (native-sink §9).
*/
#define WAI_SINK_ABI_VERSION 1
/**
* How many earlier groups of one chain [`ReceiptChains`] keeps the link hashes of, to
* tell a fork from a gap (§3 step 3). Past it, the oldest are forgotten, and a fork from
* before them reads as a gap: refused all the same, for another reason.
*/
#define CHAIN_HELD_LINKS 65536
/**
* `CausalOp::mutation_kind` for an action input (move/look/buttons + free payload).
*/
#define MUT_ACTION 1
/**
* Fixed-point fractional bits for core scales and the reconstruction
* accumulator. Scales live at `2^SCALE_FRAC`; the i128 contraction rescales by
* `>> SCALE_FRAC` after absorbing each core's per-column scale.
*/
#define SCALE_FRAC 24
/**
* Trits per packed byte. `3^5 = 243 < 256`, the near-entropy-optimal
* balanced-ternary packing (1.58 bits/trit) the ternary fabric uses.
*/
#define TRITS_PER_BYTE 5
/**
* The piece kind of a piece no source classifies: a floor-only component's (packaging
* §7.8).
*/
#define PIECE_KIND_NONE 6
/**
* Q32.32 fixed-point value.
*/
typedef struct Fx Fx;
/**
* Which kernels [`KernelPath::Fast`] runs for a convolution, a transposed convolution
* and an inverse GDN. Every set gives the same integers (the module docs); they differ
* in the instructions they use, and so in time and energy.
*/
typedef struct Isa Isa;
/**
* What a power reader's samples are, which decides what §3.1's liveness test
* over them shows and so the class a bracket over them can seal.
*/
typedef struct PowerSource PowerSource;
/**
* One native sink session (native-sink §3). Opaque to C.
*/
typedef struct wai_sink_t wai_sink_t;
typedef struct wai_buffer_t {
uint8_t *data;
uintptr_t len;
uintptr_t cap;
} wai_buffer_t;
/**
* What decoding an integer payload will cost (`wai_int_payload_declared`,
* `extensions/integer-payloads.md` §7, *Memory and work*): the decoded output's
* bytes (`output_known` 1 where they are filled), the symbols its streams code, and,
* where `cost_known` is 1, the most bytes the reference decode holds at once beyond
* the payload and the parsed set (`working_bytes`) and the networks'
* multiply-accumulates, `macs_hi·2^64 + macs_lo`.
*/
typedef struct wai_int_declared_t {
uint64_t output_bytes;
uint8_t output_known;
uint64_t symbols;
uint64_t working_bytes;
uint64_t macs_lo;
uint64_t macs_hi;
uint8_t cost_known;
} wai_int_declared_t;
/**
* What `wai_neural_decode_ex` decoded.
*
* `kind` is `WAI_DECODED_AUDIO` (`data` holds `f32` samples, `sample_rate` set),
* `WAI_DECODED_IMAGE` (`data` holds RGB8, `width` and `height` set) or
* `WAI_DECODED_VIDEO` (`data` holds the frames' RGB8 concatenated, `width`,
* `height`, `n_frames` and `fps_x_1000` set). `index` is the `WAI2` rendition
* picked (0 for a `WAI1` envelope). `path` is the decode path that ran
* (`WAI_DECODE_PATH_SOLE`, `WAI_DECODE_PATH_EXACT` or `WAI_DECODE_PATH_FLOAT`,
* extensions/determinism-tiers.md §5), which a receipt of the decode states as its
* decoder entry's `variant` (extensions/jwp-receipts.md §2.4.12). `fallback` is 1 when
* a `WAI1` envelope decoded through its manifest's `fallback` capability and 0 when
* through its `capability`; for a `WAI2` envelope `index` names the rendition, and with
* it the capability, and `fallback` is 0. Free `data` with `wai_buffer_free`.
* `wai_neural_decode_ex` writes the whole struct on every call that passes a
* non-null `out`: on failure `kind`, `path` and `fallback` are 0 and `data` is empty,
* so `data` is always safe to free.
*/
typedef struct wai_decoded_t {
uint32_t kind;
uint32_t index;
struct wai_buffer_t data;
uint32_t width;
uint32_t height;
uint32_t sample_rate;
uint32_t n_frames;
uint32_t fps_x_1000;
uint32_t path;
uint32_t fallback;
} wai_decoded_t;
/**
* How many times its lags' median absolute excess a lag's excess must reach (§8.4). Data that
* repeats exactly is not independent from lag to lag, and its noise is many times what `z` assumes;
* the median measures what it is. For a normal spread this is about 5.3 standard deviations.
*/
#define PERIOD_MEDIANS 8
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/**
* Free a buffer previously returned by any `wai_*_encode` /
* `wai_*_decode` / `wai_envelope_*` call. Safe to call with a null
* or zero-cap buffer.
*
* # Safety
* `buf.data` must have been produced by this crate.
*/
void wai_buffer_free(struct wai_buffer_t buf);
/**
* Returns a pointer to the most recent error message for this thread,
* or null if there is none. The pointer is valid until the next FFI
* call on this thread that sets an error.
*/
const char *wai_last_error(void);
/**
* Read what decoding the payload of an integer capability will cost before decoding
* it, so a sink can refuse a payload past its own size policy first
* (`extensions/integer-payloads.md` §7, *Memory and work*). `capability` is the
* envelope's capability (or the `WAI2` component's). The payload is parsed as a sink
* parses it: one that is not the format SPEC §5 pins `capability` to is
* `WAI_ERR_INVALID_ARG`, with its code in `wai_last_error`, and so is a capability
* with no pinned integer format.
*
* With `set_path` null, only the header is read: a `wai.neural.int_hyper` image's
* size is its synthesis network's, so `output_known` is 0 for it, and `cost_known` is
* 1 only for a `WIV1` with keyframe 0, which runs no network. With `set_path` naming
* the capability's parameter set — a directory holding its members by the names §9
* gives, or the file of a one-file set — every figure is filled
* (`int_payload::declared_cost`), and the set is checked against the payload as a
* decode checks it first (`set_incomplete`, `model_mismatch`, `geometry_mismatch`,
* …). The set is read as given, unverified: a pin is verified when the envelope is
* decoded. A build without `neural_int` reads no set.
*
* # Safety
* `capability` NUL-terminated; `payload` valid for `payload_len` bytes; `set_path`
* null or NUL-terminated UTF-8; `out` writable.
*/
int wai_int_payload_declared(const char *capability,
const uint8_t *payload,
uintptr_t payload_len,
const char *set_path,
struct wai_int_declared_t *out);
/**
* Builds a complete WAI file from a codec-produced payload + manifest
* fields. `manifest_json` is a UTF-8 JSON object overriding/supplying
* any fields; `payload` is the bytes from one of the codec encoders.
* Refuses (`WAI_ERR_INVALID_ARG`) a manifest that names a candidate capability
* as its capability or fallback, which an encoder MUST NOT emit (SPEC §5,
* *Candidate capabilities*), and a payload that is not the format SPEC §5 pins its
* integer capability or fallback to (*Payloads of the WAI-native integer codecs*):
* it emits through `Wai::to_emit_bytes`.
*
* # Safety
* `manifest_json` NUL-terminated; `payload` valid for `payload_len` bytes; `out` writable.
*/
int wai_envelope_pack(const char *manifest_json,
const uint8_t *payload,
uintptr_t payload_len,
struct wai_buffer_t *out);
/**
* Detect WAI version from a byte stream. Returns 1 (WAI1), 2 (WAI2),
* or 0 with an error message in `wai_last_error` for unknown magic.
*
* # Safety
* `bytes` valid for `len` bytes.
*/
int wai_envelope_detect_version(const uint8_t *bytes, uintptr_t len);
/**
* Pack a WAI2 multi-rendition envelope.
*
* - `manifest_json` must declare a `renditions` array of length `n`.
* - `payload_data` is an array of `n` byte-buffer pointers.
* - `payload_lens` is the matching array of `n` lengths.
* - The i-th payload pairs with `manifest.renditions[i]`.
*
* Refuses (`WAI_ERR_INVALID_ARG`) a table with a component, in either role,
* whose capability is a candidate (SPEC §5, *Candidate capabilities*), or whose
* payload is not the format SPEC §5 pins its integer capability to: it emits
* through `WaiMulti::to_emit_bytes`.
*
* # Safety
* All array pointers must point to valid memory of the declared length.
*/
int wai_envelope_pack_multi(const char *manifest_json,
const uint8_t *const *payload_data,
const uintptr_t *payload_lens,
uintptr_t n_payloads,
struct wai_buffer_t *out);
/**
* Parse a WAI2 envelope. Writes three outputs:
*
* - `out_manifest` — the manifest JSON exactly as the envelope carries it
* (UTF-8 bytes, no NUL), so members this library does not model survive
* - `out_renditions_json` — a JSON array with one object per component:
* `capability`, `kind`, `offset` (into `out_payload_block`), `length`, and
* `selectable` (whether SPEC §7.1 may pick it: a companion, or a companion-only
* capability, never is), plus `id`, `sha256`, `prior`, `role`, `companion_of`
* and `companion_of_id` when the entry carries them. A C sink selects with
* `wai_envelope_select` rather than by hand.
* - `out_payload_block` — every rendition's payload bytes, packed
* contiguously. The caller indexes via the JSON above.
*
* This avoids exposing a C struct array (and the ownership pain that
* comes with it). Any JSON parser the consumer already has decodes
* the rendition table in two lines.
*
* # Safety
* `bytes` valid for `len` bytes; `out_manifest` writable; `out_renditions_json` writable; `out_payload_block` writable.
*/
int wai_envelope_unpack_multi(const uint8_t *bytes,
uintptr_t len,
struct wai_buffer_t *out_manifest,
struct wai_buffer_t *out_renditions_json,
struct wai_buffer_t *out_payload_block);
/**
* Parses a WAI envelope. Writes the manifest JSON exactly as the envelope
* carries it to `out_manifest` (so `security`, and members this library does not
* model, survive) and the raw payload to `out_payload`.
*
* # Safety
* `bytes` valid for `len` bytes; `out_manifest` writable; `out_payload` writable.
*/
int wai_envelope_unpack(const uint8_t *bytes,
uintptr_t len,
struct wai_buffer_t *out_manifest,
struct wai_buffer_t *out_payload);
/**
* SPEC §7.1 selection for a `WAI2` envelope at a sink that advertises the
* capabilities in `advertised_json` (a NUL-terminated JSON array of capability
* strings). Writes the index of the picked rendition to `out_index`: the first
* entry, in SPEC §4's energy order (table order, but an entry whose capability is
* learned and carries no energy budget after every other), that is selectable (never a companion, nor a capability that is not
* dispatchable under SPEC §4: companion-only, a candidate, a record or a
* derivation), advertised, and whose payload matches its `sha256`. This call holds no
* parameter set, so an entry whose pin applies is skipped (`prior_not_held`); a
* sink that holds parameter sets decodes through `wai_neural_decode_ex`, which
* verifies each pin. Returns `WAI_ERR_NO_RENDITION` when nothing is picked, with
* each entry's index and reason in `wai_last_error`.
*
* # Safety
* `envelope` valid for `envelope_len` bytes; `advertised_json` NUL-terminated;
* `out_index` writable.
*/
int wai_envelope_select(const uint8_t *envelope,
uintptr_t envelope_len,
const char *advertised_json,
uint32_t *out_index);
/**
* Encode RGB pixels (row-major, 3 bytes per pixel) as PNG.
*
* # Safety
* `rgb` must point to a valid RGB buffer of at least `len` bytes;
* `out` must be a writable `WaiBuffer*`. Pass `(null, 0)` for empty.
*/
int wai_image_png_encode(const uint8_t *rgb,
uintptr_t len,
uint32_t h,
uint32_t w,
struct wai_buffer_t *out);
/**
* Decode a PNG byte stream to RGB. Returns `(rgb, h, w)`.
*
* A picture past the reader limits of SPEC §2 (wider or taller than
* [`IMAGE_MAX_SIDE`](crate::codecs::image::IMAGE_MAX_SIDE) or holding more than
* [`IMAGE_MAX_PIXELS`](crate::codecs::image::IMAGE_MAX_PIXELS) pixels) is refused with
* `WAI_ERR_CODEC` from the size it declares, before it decodes; the message begins
* `image_too_large`.
*
* # Safety
* `bytes` valid for `len` bytes; `out` writable; `out_h` writable; `out_w` writable.
*/
int wai_image_png_decode(const uint8_t *bytes,
uintptr_t len,
struct wai_buffer_t *out,
uint32_t *out_h,
uint32_t *out_w);
/**
* # Safety
* `rgb` valid for `len` bytes; `out` writable.
*/
int wai_image_avif_encode(const uint8_t *rgb,
uintptr_t len,
uint32_t h,
uint32_t w,
uint8_t quality,
struct wai_buffer_t *out);
/**
* A picture past the reader limits of SPEC §2 (wider or taller than
* [`IMAGE_MAX_SIDE`](crate::codecs::image::IMAGE_MAX_SIDE) or holding more than
* [`IMAGE_MAX_PIXELS`](crate::codecs::image::IMAGE_MAX_PIXELS) pixels) is refused with
* `WAI_ERR_CODEC` from the size it declares, before it decodes; the message begins
* `image_too_large`.
*
* # Safety
* `bytes` valid for `len` bytes; `out` writable; `out_h` writable; `out_w` writable.
*/
int wai_image_avif_decode(const uint8_t *bytes,
uintptr_t len,
struct wai_buffer_t *out,
uint32_t *out_h,
uint32_t *out_w);
/**
* `quality = 0` ⇒ lossless. Otherwise butteraugli distance proxy
* (higher quality = smaller distance internally).
*
* # Safety
* `rgb` valid for `len` bytes; `out` writable.
*/
int wai_image_jxl_encode(const uint8_t *rgb,
uintptr_t len,
uint32_t h,
uint32_t w,
uint8_t quality,
struct wai_buffer_t *out);
/**
* A picture past the reader limits of SPEC §2 (wider or taller than
* [`IMAGE_MAX_SIDE`](crate::codecs::image::IMAGE_MAX_SIDE) or holding more than
* [`IMAGE_MAX_PIXELS`](crate::codecs::image::IMAGE_MAX_PIXELS) pixels) is refused with
* `WAI_ERR_CODEC` from the size it declares, before it decodes; the message begins
* `image_too_large`.
*
* # Safety
* `bytes` valid for `len` bytes; `out` writable; `out_h` writable; `out_w` writable.
*/
int wai_image_jxl_decode(const uint8_t *bytes,
uintptr_t len,
struct wai_buffer_t *out,
uint32_t *out_h,
uint32_t *out_w);
/**
* # Safety
* `samples` valid for `n` `f32`s; `out` writable.
*/
int wai_audio_opus_encode(const float *samples,
uintptr_t n,
uint32_t sr,
int32_t bitrate_bps,
struct wai_buffer_t *out);
/**
* Output past the reader limit of SPEC §2,
* [`AUDIO_DECODED_MAX_SAMPLES`](crate::codecs::audio::AUDIO_DECODED_MAX_SAMPLES)
* samples, is refused with `WAI_ERR_CODEC`; the message begins
* `audio_decoded_too_long`.
*
* # Safety
* `bytes` valid for `len` bytes; `out` writable; `out_sr` writable.
*/
int wai_audio_opus_decode(const uint8_t *bytes,
uintptr_t len,
struct wai_buffer_t *out,
uint32_t *out_sr);
/**
* # Safety
* `samples` valid for `n` `f32`s; `out` writable.
*/
int wai_audio_flac_encode(const float *samples,
uintptr_t n,
uint32_t sr,
struct wai_buffer_t *out);
/**
* Output past the reader limit of SPEC §2,
* [`AUDIO_DECODED_MAX_SAMPLES`](crate::codecs::audio::AUDIO_DECODED_MAX_SAMPLES)
* samples, is refused with `WAI_ERR_CODEC`; the message begins
* `audio_decoded_too_long`.
*
* # Safety
* `bytes` valid for `len` bytes; `out` writable; `out_sr` writable.
*/
int wai_audio_flac_decode(const uint8_t *bytes,
uintptr_t len,
struct wai_buffer_t *out,
uint32_t *out_sr);
/**
* # Safety
* `data` valid for `len` bytes; `out` writable.
*/
int wai_text_zstd_encode(const uint8_t *data,
uintptr_t len,
int32_t level,
struct wai_buffer_t *out);
/**
* Decode a `wai.text.zstd` payload within the reader limits of SPEC §2: at most
* [`TEXT_DECODED_MAX_LEN`](crate::codecs::text::TEXT_DECODED_MAX_LEN) bytes of output
* and [`TEXT_WINDOW_MAX_LEN`](crate::codecs::text::TEXT_WINDOW_MAX_LEN) bytes of
* window. A payload past either is refused with `WAI_ERR_CODEC`; the message begins
* `text_decoded_too_long` or `text_window_too_large`.
*
* # Safety
* `bytes` valid for `len` bytes; `out` writable.
*/
int wai_text_zstd_decode(const uint8_t *bytes, uintptr_t len, struct wai_buffer_t *out);
/**
* # Safety
* `data` valid for `len` bytes; `out` writable.
*/
int wai_text_xz_encode(const uint8_t *data,
uintptr_t len,
uint32_t level,
struct wai_buffer_t *out);
/**
* Decode a `wai.text.xz` payload within the same limits as
* [`wai_text_zstd_decode`], the window limit applying to the dictionary.
*
* # Safety
* `bytes` valid for `len` bytes; `out` writable.
*/
int wai_text_xz_decode(const uint8_t *bytes, uintptr_t len, struct wai_buffer_t *out);
/**
* Encode a sequence of `n` RGB frames as AV1.
*
* # Safety
* `rgb` valid for `len` bytes; `out` writable.
*/
int wai_video_av1_encode(const uint8_t *rgb,
uintptr_t len,
uint32_t n,
uint32_t h,
uint32_t w,
uint32_t fps_num,
uint32_t fps_den,
uint8_t lossless,
uint8_t quality,
struct wai_buffer_t *out);
/**
* Decode an AV1 WAI payload to a packed RGB buffer `n*h*w*3` bytes.
*
* A payload past the reader limits of SPEC §2 (more than
* [`VIDEO_MAX_TEMPORAL_UNITS`](crate::codecs::video::VIDEO_MAX_TEMPORAL_UNITS)
* temporal units, or frames past the picture limits) is refused from its header;
* the message begins `video_too_large`. Since the buffer holds every frame, so is
* one whose frames would take more than
* [`AV1_DECODE_DEFAULT_MAX_LEN`](crate::codecs::video::AV1_DECODE_DEFAULT_MAX_LEN)
* bytes together (`video_decoded_too_large`), and one whose frames differ in size.
*
* # Safety
* `bytes` valid for `len` bytes; `out` writable; `out_n` writable; `out_h` writable; `out_w` writable; `out_fps_num` writable; `out_fps_den` writable.
*/
int wai_video_av1_decode(const uint8_t *bytes,
uintptr_t len,
struct wai_buffer_t *out,
uint32_t *out_n,
uint32_t *out_h,
uint32_t *out_w,
uint32_t *out_fps_num,
uint32_t *out_fps_den);
/**
* Decode a `wai.neural.<audio>` envelope (encodec32 / dac / mimi /
* wavtokenizer / snac). Writes mono `f32` samples into `out_samples`; the
* caller reads them as `float*` of length `out_samples.len / 4`.
*
* # Safety
* `envelope` valid for `envelope_len` bytes. `model_path` NUL-terminated
* UTF-8 path to the decoder. `out_samples` writable `WaiBuffer*`.
* `out_sample_rate` writable `uint32_t*` (or null to skip).
*/
int wai_neural_decode_audio(const uint8_t *envelope,
uintptr_t envelope_len,
const char *model_path,
struct wai_buffer_t *out_samples,
uint32_t *out_sample_rate);
/**
* Decode a neural image envelope. Writes packed RGB (row-major, 3 bytes/pixel)
* into `out_rgb`; writes width/height into `*out_width` / `*out_height`.
*
* # Safety
* See `wai_neural_decode_audio`.
*/
int wai_neural_decode_image(const uint8_t *envelope,
uintptr_t envelope_len,
const char *model_path,
struct wai_buffer_t *out_rgb,
uint32_t *out_width,
uint32_t *out_height);
/**
* Decode a neural video envelope. Writes all frames concatenated (frame 0
* RGB, then frame 1 RGB, …) into `out_frames_concat`; the caller splits at
* `width*height*3` strides.
*
* # Safety
* See `wai_neural_decode_audio`.
*/
int wai_neural_decode_video(const uint8_t *envelope,
uintptr_t envelope_len,
const char *model_path,
struct wai_buffer_t *out_frames_concat,
uint32_t *out_n_frames,
uint32_t *out_width,
uint32_t *out_height,
uint32_t *out_fps_x_1000);
/**
* Decode a `WAI1` or `WAI2` envelope against the parameter sets in
* `registry_json`: a NUL-terminated JSON object mapping each capability to an
* array of paths. The first path is the registered artifact; the others are
* further sets a pin may resolve against (a set and its successor). Every pin is
* verified first (SPEC §3.1); a `WAI2` rendition is picked by SPEC §7.1. With
* `flags & WAI_DECODE_STRICT`, SPEC §7's replicate rule applies too. A capability
* whose output has no `wai_decoded_t` kind (integer video, PCM, splat attributes) is
* not advertised, whatever `registry_json` says: dispatch moves on past it before
* decoding, and when nothing else decodes the error names it.
*
* `*out` is written on every call with a non-null `out`, before anything else is
* read: on failure it holds `kind` 0 and an empty `data`, so the caller may free
* `out->data` whatever the status.
*
* # Safety
* `envelope` valid for `envelope_len` bytes; `registry_json` NUL-terminated;
* `out` a writable `WaiDecoded*`, which need not be initialised.
*/
int wai_neural_decode_ex(const uint8_t *envelope,
uintptr_t envelope_len,
const char *registry_json,
uint32_t flags,
struct wai_decoded_t *out);
/**
* The ABI version this library implements, [`WAI_SINK_ABI_VERSION`].
*/
uint32_t wai_sink_abi_version(void);
/**
* The microseconds since 1970-01-01T00:00:00Z on this host's clock: the time a host passes to
* the calls below when it has no clock of its own to hand.
*/
uint64_t wai_sink_now_us(void);
/**
* Open a session (native-sink §3) at `start_us` under `config_json` (§3.1):
* `{"channel", "owner", "presentation", "window_us", "ad_classes", "content_addressed",
* "require", "unseen_grace_ms", "idle_ms"}`, of which `channel` and `owner` are required.
*
* With `seed` null, the session key is fresh from the operating system's random generator, as
* stream-audit §3.2 requires. A 32-byte `seed` derives it instead: for conformance vectors and
* tests only, never for a viewer's session. Writes the handle to `out`; free it with
* [`wai_sink_free`].
*
* # Safety
* `config_json` NUL-terminated; `seed` null or valid for `seed_len` bytes; `out` writable.
*/
int wai_sink_open(const char *config_json,
const uint8_t *seed,
uintptr_t seed_len,
uint64_t start_us,
struct wai_sink_t **out);
/**
* Free a session. No record is signed: a host that wants the bundle ends the session first
* ([`wai_sink_end`]). Safe with null.
*
* # Safety
* `s` null or a handle from [`wai_sink_open`], not used after this call.
*/
void wai_sink_free(struct wai_sink_t *s);
/**
* The session's identity (§3.2) as JSON: `{"channel", "owner", "player", "session",
* "start_us", "presentation", "ended"}`.
*
* # Safety
* `s` a handle; `out` writable.
*/
int wai_sink_info(const struct wai_sink_t *s, struct wai_buffer_t *out);
/**
* The name of a playlist's receipt file relative to the playlist, `mr/<BLAKE3>.json`
* (http-delivery §8.6), as UTF-8 bytes: the host fetches it beside the playlist.
*
* # Safety
* `playlist` valid for `len` bytes; `out` writable.
*/
int wai_sink_receipt_name(const uint8_t *playlist, uintptr_t len, struct wai_buffer_t *out);
/**
* A playlist the player fetched from `url` (after redirects), with the playlist receipt the host
* fetched beside it (`receipt` null when there is none, or none was served), verified and taken
* into the session (§4.2). Writes the verdict: `{"kind", "listing", "receipt", "receipt_name",
* "step", "need_parent", "refused", "present", "segments", "ads"}`.
*
* When `need_parent` is a name, the chain of the playlist's live receipts needs that parent: the
* host fetches it relative to the playlist, hands it over with [`wai_sink_playlist_parent`], and
* calls this again with the same playlist.
*
* # Safety
* `s` a handle; `url` NUL-terminated; `bytes` valid for `len`; `receipt` null or valid for
* `receipt_len`; `out` writable.
*/
int wai_sink_playlist(const struct wai_sink_t *s,
const char *url,
const uint8_t *bytes,
uintptr_t len,
const uint8_t *receipt,
uintptr_t receipt_len,
struct wai_buffer_t *out);
/**
* Hand over a parent receipt file a playlist's verdict named in `need_parent`: `name` as the
* verdict gave it (`mr/<hash>.json`), `bytes` what was served, or null when nothing was
* (http-delivery §8.6, `playlist_receipt_parent_missing`).
*
* # Safety
* `s` a handle; `url`, `name` NUL-terminated; `bytes` null or valid for `len`.
*/
int wai_sink_playlist_parent(const struct wai_sink_t *s,
const char *url,
const char *name,
const uint8_t *bytes,
uintptr_t len);
/**
* A response body the player received, with its content codings removed (§4.3). `meta_json`:
* `{"url", "t_us", "media", "status", "cmsd_static", "cmsd_dynamic"}`, of which `url` and `t_us`
* are required. Writes the verdict: `{"sha256", "cid", "listing", "bound", "media", "key",
* "acknowledged", "refused", "present"}`. With `"present": false` the host does not hand the
* bytes to its decoder.
*
* # Safety
* `s` a handle; `meta_json` NUL-terminated; `bytes` valid for `len`; `out` writable.
*/
int wai_sink_object(const struct wai_sink_t *s,
const char *meta_json,
const uint8_t *bytes,
uintptr_t len,
struct wai_buffer_t *out);
/**
* A log event (§5.2): `start`, `present`, `stall-start`, `stall-end`, `end` or `abandon`, at
* `t_us`.
*
* # Safety
* `s` a handle; `name` NUL-terminated.
*/
int wai_sink_event(const struct wai_sink_t *s, const char *name, uint64_t t_us);
/**
* An observation of playback (§5.1): `{"t_us", "playing", "visible_bp", "audible",
* "program_ms", "seeked", "interaction"}`, at least every 200 ms while the player presents.
* Writes `{"end": null}`, or `{"end": "hidden"}` / `{"end": "idle"}` when the session's
* termination rule ends it (§6.1): the host then stops its player and ends the session so.
*
* # Safety
* `s` a handle; `obs_json` NUL-terminated; `out` writable.
*/
int wai_sink_observe(const struct wai_sink_t *s, const char *obs_json, struct wai_buffer_t *out);
/**
* A role's energy over the session (§7): `{"role", "joules_micro", "energy_provenance",
* "energy_uncertainty", "energy_counter_filtering", "energy_calibration_ref"}`, the class written
* as jwp-receipts §2.4.5 writes it. `joules_micro` 0 with no class is the unmetered marker;
* `{"role", "absent": true}` removes the role's entry. A session opens with the marker for the
* sink decode (3) and the display (4).
*
* # Safety
* `s` a handle; `entry_json` NUL-terminated.
*/
int wai_sink_energy(const struct wai_sink_t *s, const char *entry_json);
/**
* Attach another signed record of the session (stream-audit §8.3), by its registered name.
*
* # Safety
* `s` a handle; `name` NUL-terminated; `bytes` valid for `len`.
*/
int wai_sink_attach(const struct wai_sink_t *s,
const char *name,
const uint8_t *bytes,
uintptr_t len);
/**
* The `application/cmcd` batch of the log's observations not yet taken (stream-audit §7.2), as
* UTF-8 bytes, one report per line; empty when there is none. The host posts it to the
* collector's `v1/cmcd` while the session runs.
*
* # Safety
* `s` a handle; `out` writable.
*/
int wai_sink_take_cmcd(const struct wai_sink_t *s, struct wai_buffer_t *out);
/**
* End the session (stream-audit §8.2) at `t_us`, `ended` one of `ended`, `user`, `hidden`,
* `idle`, `error`: its records are signed, and the bundle (stream-audit §9) is written to `out`
* as the JSON the host posts to the collector's `v1/sessions`.
*
* # Safety
* `s` a handle; `ended` NUL-terminated; `out` writable.
*/
int wai_sink_end(const struct wai_sink_t *s,
const char *ended,
uint64_t t_us,
struct wai_buffer_t *out);
/**
* Verify a bundle as the owner's collector does (stream-audit §10), for the owner `owner` (32
* bytes) serving the channels named in `channels_json` (a JSON array of names). Writes the
* outcome JSON of stream-audit §10.3: `{"outcome": "accept", …}` or `{"outcome": "refuse", "reason", "at"}`.
*
* # Safety
* `bundle` valid for `len`; `owner` valid for 32 bytes; `channels_json` NUL-terminated; `out`
* writable.
*/
int wai_audit_verify_bundle(const uint8_t *bundle,
uintptr_t len,
const uint8_t *owner,
const char *channels_json,
struct wai_buffer_t *out);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif /* WAI_H */