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.

baseMs number
the configured connectTimeout
bytes number
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.

options Object
options.env object
the Env (sole registry surface)
options.model string
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.

Protocol Function
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

connection object
@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