PUBLIC MODULE · lib/io.js
IO
lib/io.js — IO: provider IO/schema conversion, nothing else.
This module depends on lib/context.js and lib/env.js. It re-exports the provider contract and HTTP defaults for IO consumers and provider authors.
An IO instance carries NO context — every write() is a blank-slate context-to-provider-request conversion. It holds connection state for the active request (a provider connection is created and closed for each request) and exposes:
settings — provider-namespaced LIVE settings view (via Env) tools() — current tool catalog, per-instance availability selection applied (between-request refresh visible) authSet(a) — routes to Env.authSet(endpoint name, a) write(context, callbacks?, options?) — one request, resolves with the terminal done/error event kill() — cancel active request, emit terminal partial, close, permanently disconnect
State machine per instance: idle → sending → reading → idle, repeating. Sending while not idle is a contract error (no concurrent in-flight requests). After kill() the instance is "closed" forever; the caller constructs a replacement.
IO owns the GLOBAL ACTIVE-IO ledger (Env.activeIO): an instance adds ITSELF for exactly a request's in-flight duration and removes itself the moment the IO settles — a tool call requested, a turn ended, a timeout (lib/io/request.js). The ledger's size is the settings.maxActive measure (maxActive caps concurrent IO, never agents: tool calls are client work and hold no slot). IO knows nothing about agents — the set carries instances, never identities.
IO sanitizes outgoing requests (headers/body from the connector) and validates converted responses (valid response events; message metadata rides along — tolerant reader). Metadata RECORDS (context entries with a string type — harness/tool-owned data, isRecord) and empty messages are filtered OUT of every provider-bound context: they persist in the session and ride the agent's array, but the model never sees them. Errors surface in the auth/network/provider/malformed taxonomy (+ "cancelled" on kill).
Per-request timeouts (each: write options > constructor > provider- namespaced settings > provider metadata > default; all accept a millisecond numeral or a unit string via lib/env/duration.js): - timeout overall cap per request (default 1048575ms) — an agent may legitimately work for a long time; - connectTimeout no response from the provider at all (default 30000ms) — a hung connection. Its connection budget is computed from the serialized request body; callers should treat it as a guardrail, not a latency prediction; - stuckTimeout no DATA between message events while reading (default 120000ms) — a stuck model; every frame (text/thinking/tool-call block or delta) resets it, so long-but-active generations never trip it.
class IO class
One provider IO session: context in, normalized response events out.
constructor({ env, model, url, timeout, connectTimeout, stuckTimeout, settings, tools, onData, onLog } = {…}) constructor
Configure one provider IO session: resolve the provider module from the registered endpoint and resolve the model, endpoint URL, and three timeouts from options > provider settings > provider metadata > defaults.
get state() getter
The request state machine's current state. @returns {"idle"|"sending"|"reading"|"closed"}
get settings() getter
live provider-namespaced settings view (explicit overrides merged over the Env namespace)
setOption(key, value) method
Set/clear a per-invocation settings override AFTER construction (e.g. Agent's /agent-thinking toggling think on a live connection).
tools() method
the current publishable tool catalog (availability applied)
authSet(auth, options) method
Route auth persistence to the endpoint's namespace and refresh the live settings view.
get requestSignal() getter
the in-flight request's abort signal (used by the HTTP backend)
get currentModel() getter
effective model: per-request override wins over the instance default
get contextUsage() getter
The provider-reported context readout of the CURRENT/last request: {used, total} in tokens, each undefined when the provider hasn't reported it. Providers update it during a request via setContextUsage() (e.g. from a usage frame or model metadata); IO itself fills used from the terminal usage envelope when the provider left it unset. Consumers (Agent) read it after write() resolves; missing data is their cue to approximate.
setContextUsage({ used, total } = {…}) method
Report actual context consumption and/or the model's available context window (provider → IO channel; connectors call this from their translators/metadata surfaces). Finite numbers merge over the current report; anything else is ignored.
get planUsage() getter
The provider-reported PLAN/QUOTA readout (rate limits, subscription allowances): {label?, quotas} where each quota entry is {total?, remaining?, used?, reset?} — whatever the provider publishes, nothing invented. null until the provider reports. Unlike contextUsage it is LAST-KNOWN (never reset per request — a quota snapshot stays meaningful between requests).
setPlanUsage({ label, quotas } = {…}) method
Report plan/quota usage (provider → IO channel; connectors call this from their reportPlanUsage hook or metadata surfaces). Tolerant reader: only finite numbers and non-empty strings are kept, quota entries merge key-by-key over the last-known report.
write(context, callbacks = {…}, options = {…}) method
Run one provider request over a complete context.
kill() method
Cancel the active request (terminal partial emitted by the in-flight write), close the connection, permanently disconnect the instance. Resolves when finalization completes. Idempotent.
sanitizeRequest(msg) function
Sanitize the connector's outgoing msg into the [headers, body] convention: headers a plain object with string-valued entries (undefined/null/function entries dropped, values stringified), body JSON-serializable or nil. Throws ProviderError("malformed") on unserializable connector output.
msg*
Returns [object, *] — sanitized [headers, body]
Defined in lib/io/sanitize.js
bodyBytes(body) function
The request body's size in bytes as it would go on the wire (UTF-8 JSON, BEFORE any transport compression) — 0 for a nil body.
body*- a sanitized (JSON-serializable) body or null
Returns number
Defined in lib/io/sanitize.js
connectBudget(baseMs, bytes) function
The connection-timeout budget for one request: the base timeout plus one millisecond per request-body byte (before compression) — larger prompts get proportionally more time to produce a first response.
baseMsnumber- the configured connectTimeout
bytesnumber- the request body's byte size (bodyBytes)
Returns number — milliseconds
Defined in lib/io/request.js
resolveTimeout({ env, model, timeout, settings } = {…}) function
The effective overall request timeout without constructing a connection: explicit > endpoint settings > provider metadata > default. Accepts ms numerals or unit strings. Throws on an unknown endpoint, like IO itself.
optionsObjectoptions.envobject- the Env (sole registry surface)
options.modelstring- registered `<endpoint>/<model>` selector
[options.timeout]number|string- explicit override
[options.settings]object- per-invocation overrides over the namespace
Returns number — milliseconds
Defined in lib/io/request.js
Env unknown
The global environment constructor used by IO and provider authors.
Defined in lib/env.js
Context unknown
The Context namespace for validating every provider-bound request.
Defined in lib/context.js
class ProviderError extends Error class
Provider/transport error with a stable failure class.
Defined in lib/env/provider-error.js
constructor(kind, message, detail = {…}) constructor
Build a stable classified provider error.
classifyError(err, providerName) function
Classify a raw error into the stable provider taxonomy.
Defined in lib/env/provider.js
defineProvider(Protocol, { name } = {…}) function
Complete a standalone provider class with OpenAI-compatible defaults. The returned class is the sole runtime contract; function-module plugins are intentionally unsupported in this pre-release core.
ProtocolFunction- plugin class
Returns Function — completed provider class
Defined in lib/env/provider.js
class HttpStatusError extends Error class
HTTP response carrying a non-2xx status.
Defined in lib/env/http.js
constructor(status, statusText, body) constructor
Build the error from a non-2xx response (the body's first 200 characters ride in the message).
defaultConnect(url, aiio) function
stateless HTTP connection
Returns {url: string, aiio: object} — stateless HTTP connection
Defined in lib/env/http.js
async defaultSend(connection, msg) function
Default send: msg = [headers, body].
Defined in lib/env/http.js
async defaultSendHeaders(connection, headers) function
@param {object} headers plain object
connectionobject- @param {object} headers plain object
Defined in lib/env/http.js
async defaultSendBody(connection, body) function
Completes the request: POSTs the JSON body (nil body -> no payload) and stores the Response for defaultRead.
Defined in lib/env/http.js
async defaultRead(connection) function
Blocking-await line reader: resolves the next whole line-delimited JSON message, nil at end-of-stream.
Returns Promise<object|null>
Defined in lib/env/http.js
async defaultClose(connection) function
Teardown: cancel the body stream; idempotent.
Defined in lib/env/http.js