Typed workspace request clients v1
September 10, 2026 ยท View on GitHub
Status: implemented bounded profile; HOSTED GREEN under the v0.4.0 release baseline. Historical local, authoring-time, ignored, or separately provisioned observations below retain their narrower scope; public promotion and broader product completion remain separately gated.
Audience: agent client authors, editor integrators and compiler contributors.
The v5 client generator provides additive structural types for complete selected request parameters, including recursively nested intentions, expressions and recovery objects. These types come from the existing compiler-owned schema bundle. They do not introduce another constructor grammar or replace compiler admission.
Additive API
Each selected method receives <Method>TypedParams and
request_<method>_typed. For example, candidate/apply-intent exposes
CandidateApplyIntentTypedParams and request_candidate_apply_intent_typed.
The existing CandidateApplyIntentParams, request builder, generic result
decoder and typed response decoder remain
available. Disabled methods receive no typed request helper.
The new builder serializes the typed parameters through the same selected-method request function as the old builder. Request IDs, outer parameter checks and the 64 KiB request limit keep their existing behavior. Builders perform no I/O, choose no host policy and cannot enable a disabled operation.
const params: CandidateApplyIntentTypedParams = {
image_revision: imageRevision,
candidate_revision: candidateRevision,
intent: {
kind: "replace_function_body",
target: "calculator.add",
body: {
kind: "let",
name: "answer",
value: { kind: "i64", value: 7 },
body: { kind: "place", name: "answer" }
}
}
};
const frame = request_candidate_apply_intent_typed("edit-1", params);
This constructs a request frame; it does not apply, verify or publish the change. The caller must use revisions returned by its live session and a target admitted by that candidate. A described constructor can still fail scope, type, ownership, effect, contract, cleanup or target checks.
Schema ownership and recursion
The request model follows the selected methods' parameter schemas and resolves
absolute schema identifiers and document-local $defs references within the
provided bundle. Local definitions retain their document scope. Unselected
documents do not introduce extra method helpers or constructor authority.
Named shapes are reserved before following their dependencies, allowing finite
recursive values such as nested calls, bindings and conditional expressions.
Unguarded cycles through only aliases and unions fail generation; recursion
must pass through a value structure such as an object or array.
Missing references and unsupported shapes also fail closed. Deterministic
RequestType names belong to the generated artifact, not to semantic identities;
the method aliases are the public entry points.
Object fields, required versus optional properties, nullable alternatives,
arrays, literal choices and unions retain their structural meaning. Types do
not prove numeric or byte bounds, name exclusions, uniqueness, expression budgets
or oneOf exclusivity. The existing builder validates the outer request only;
the compiler still validates the complete nested constructor. Directly creating
or deserializing a generated type is not an admission API.
Language boundaries
TypeScript uses recursive structural types and literal discriminants. Its number type does not represent every exact JSON integer, and static types cannot prove integer ranges. Callers remain responsible for avoiding values already rounded by JavaScript before serialization.
Python 3.11 uses functional typed dictionaries and forward references for recursive fields and alternatives. Required and optional fields remain distinct. These are annotations, not runtime constructor validation; the compiler still decides whether the supplied dictionary describes an admitted change.
Rust uses request-specific integer and optional-presence helpers. Boxed named edges and transparent wrappers permit recursive types without changing their JSON representation. Closed object types reject unknown fields on direct serde deserialization, but this is only part of the compiler's grammar and admission contract. Signed and unsigned JSON integers retain their representable range.
Bounds and evidence
The model bounds schema traversal and generated type source: 4,096 definitions, 65,536 visits, depth 128, 16 MiB of retained schema keys and 900 KiB of generated type source. The existing complete discovery payload bound still applies to the combined generated client. These are generation limits, not a guarantee of total process memory, runtime recursion depth or latency.
Focused model/emitter regressions and tests/image_typed_request_clients_v5.rs
author recursion, local-scope resolution, deterministic selected profiles,
legacy helper preservation and nested request submission. Python, Rust, and provisioned TypeScript harnesses are authored to compile or resolve their generated public types, emit exact request frames, submit them to ordinary compiler admission, and require hostile unbound places to reject. The implemented expanded corpus has hosted-green release evidence. These selected request paths do not establish a complete SDK, every method, external package ergonomics, every possible host/platform combination, or completion-matrix promotion.