PUBLIC MODULE · lib/context.js
Context
lib/context.js — Context: the shared conversation data model.
PUBLIC MODULE (owner of lib/context/). At the bottom of the dependency chain, it imports no other public module; Env, IO, Agent, CLI, and TUI depend on it, never the reverse. Private helpers live in lib/context/; consumers use this façade's named exports or its static Context namespace.
parseInput(input) function
Parse a buffered input string (such as CLI input after EOF) into a context array.
class Context class
Canonical context module namespace; its API is exposed as static members.
MessageType = Object.freeze({…}) constant
Numeric message types. 0 is reserved.
Defined in lib/context/types.js
ContentType = Object.freeze({…}) constant
Content block discriminators.
Defined in lib/context/types.js
textContent(text) function
Wrap plain text in a text content block. @returns {TextContent}
Defined in lib/context/types.js
userMessage(text, metadata = undefined) function
user message wrapping text or preserving ordered blocks
Returns Message — user message wrapping text or preserving ordered blocks
Defined in lib/context/types.js
systemMessage(text) function
system message wrapping plain text
Returns Message — system message wrapping plain text
Defined in lib/context/types.js
assistantMessage(content = []) function
assistant message from content blocks
Returns Message — assistant message from content blocks
Defined in lib/context/types.js
mimetypeOf(block) function
Return a content block's canonical media type.
Defined in lib/context/types.js
MIME_BY_EXTENSION = Object.freeze({…}) constant
Context-owned media-type map and byte detection for content blocks.
Defined in lib/context/mime.js
detectMime({ path, buffer } = {…}) function
Detect a media type from a filename extension or recognized leading bytes.
Defined in lib/context/mime.js
binaryContent(path, buffer) function
Build a canonical base64 binary Context block without leaking its source path.
Defined in lib/context/mime.js
fileMessage(path, buffer) function
Wrap one local file's bytes as a canonical user message.
Defined in lib/context/mime.js
isMessage(msg) function
Is this a core-shaped message (a numeric type and a content array)?
msg*
Returns boolean — true when msg has the core message shape
Defined in lib/context/validate.js
isRecord(msg) function
Is this a metadata RECORD (a string type, never a numeric message type)? Records are harness/tool-owned data entries that may share the context array and the session file with messages (the note tool's compaction-surviving store backup is the first). A record is NEVER a message: validators skip it, appendMessage passes it through unmerged, IO filters it from every provider-bound context, and the session file's own session-metadata header record is the loader's one exclusion (it maps the file, it is not context content).
msg*
Returns boolean — true when msg carries a string `type`
Defined in lib/context/validate.js
isContext(ctx) function
Is this a context (an array of core-shaped messages and/or records)?
ctx*
Returns boolean — true when ctx is an array of messages/records
Defined in lib/context/validate.js
hasContent(msg) function
Has this message any CONTENT a provider can consume? A block with no payload — a text/thinking block whose text is empty, a block reduced to its discriminator alone — is not content; an empty content array is not content either. Chat-completions dialects serialize an empty assistant message as content: null and providers 400 the whole request over it (corrupted sessions), so emptiness is a hard contract, not a style point.
msg*
Returns boolean
Defined in lib/context/validate.js
validateMessage(msg, at = "message") function
Validate a message's CORE SHAPE, throwing on a violation. Returns the SAME object reference — metadata is never copied, stripped, or reordered. Emptiness is deliberately NOT part of the shape: appendMessage REFUSES (drops) an empty incoming message, and IO DROPS empty messages from every provider-bound context (no dialect can carry one), while a merge that consumed an incoming message's whole payload into the previous message may legitimately leave it empty inside the live array.
msg*[at]string- address hint for error messages (e.g. "context[2]")
Returns object — msg, unchanged
Defined in lib/context/validate.js
validateContext(ctx) function
Validate a context array. Returns the same array reference.
ctx*
Returns Array — ctx, unchanged
Defined in lib/context/validate.js
EventType = Object.freeze({…}) constant
The full normalized event vocabulary.
Defined in lib/context/events.js
callbackName(eventName) function
Map an event name to its camelCase callback name. "text_delta" -> "onTextDelta"; "toolcall_start" -> "onToolcallStart".
eventNamestring
Returns string
Defined in lib/context/events.js
isResponseEvent(event) function
Is this a well-formed normalized response event (a known type; indexed events carry a non-negative integer contentIndex)?
event*
Returns boolean — true for a well-formed normalized response event
Defined in lib/context/events.js
validateResponseEvent(event) function
Validate a normalized response event (used by IO to check connector output). Returns the same object; throws on violation.
event*
Returns object
Defined in lib/context/events.js
normalizeCallbacks(callbacks = {…}, binding = {…}) function
Build the full callback set for a binding.
[callbacks]Object- consumer-supplied callbacks. A function is used as-is; explicit false/null selects a no-op; undefined gets the binding default.
bindingObject- binding-appropriate defaults
[binding.onData](event:object)=>void- receives every event whose callback was omitted (stdout replacement)
[binding.onLog](line:string)=>void- receives error reports (stderr replacement)
[binding.onTerminal](event:object)=>void- completes the binding; fires on done/error even when the consumer supplied its own terminal callback (unless itself false/null)
Returns Object — complete callback set keyed by camelCase names
Defined in lib/context/events.js
dispatch(set, event) function
Dispatch one event through a (normalized) callback set.
setObject- callback set from normalizeCallbacks
eventobject- a normalized response event
Defined in lib/context/events.js
parseContext(input) function
Parse buffered CLI input into a context array per the shared grammar. Pure function — testable without a process.
inputstring- complete stdin text (post-EOF)
Returns Array<object> — context array of messages
Defined in lib/context/parse.js
createAssembler() function
Create an assembler that consumes normalized IO response events into one assistant message. The message is partial until done; at any point message() returns what has been assembled so far (this is what cancellation persists).
Returns {consume: (event: object) => void, message: () => object}
Defined in lib/context/assemble.js
assemblyCallbacks(assembler) function
The callback set (camelCase, matching lib/context/events.js) that assembles a response — Context "supplies the callback set".
assemblerReturnType<typeof createAssembler>
Returns Object — callbacks keyed onStart/onTextDelta/.../onDone/onError
Defined in lib/context/assemble.js
foldContent(content) function
Fold ADJACENT same-sub-type text/thinking blocks within one content array (a stream with repeated indexes, or a cross-message merge, can leave runs of them — one logical block should BE one block). Returns a NEW array (blocks themselves are shared unless folded).
contentArray
Returns Array — folded content
Defined in lib/context/merge.js
mergeableMessages(a, b) function
Can two CONSECUTIVE messages merge into one? Same numeric type, never a ToolResult (each result's callId/name/error linkage is its own — merging would destroy call→answer addressing), and exactly matching metadata. Metadata is a message boundary when it differs: in particular, a subtype: "chat" message cannot merge with normal user input. System, user and assistant continuations may merge only when their non-message keys match.
aobjectbobject
Returns boolean
Defined in lib/context/merge.js
appendMessage(context, message, { merge = true } = {…}) function
Append a message to a caller-owned context, MERGING when possible: the message's own adjacent same-sub-type blocks fold first; when the context's last message is mergeable with it (same type, no linkage), their content concatenates (and re-folds) instead of appending a new message. Consecutive same-type text messages — queued user input, repeated /system, a cancel-partial assistant followed by the next turn's — become ONE message, so the context (and every replay of it) shows one merged block per sub-type, not a chain of fragments. Mutates the array in place.
contextArray- caller-owned array
messageobject
Returns object — the stored message (the PREVIOUS one when merged)
Defined in lib/context/merge.js
at(context, i) function
Address a message: context[i], validated (throws on a bad integer index or shape).
contextArrayinumber
Returns object — context[i], validated
Defined in lib/context/edit.js
blockAt(context, i, j) function
Address a content block: context[i].content[j], validated (RangeError when j is out of range).
contextArrayinumberjnumber
Returns object — context[i].content[j], validated
Defined in lib/context/edit.js
rebuildMessage(msg) function
Rebuild a message from recognized schema fields only — the stale provider/cache identifier cleanup. See the module header for the field policy.
msgobject
Returns object — a NEW message object
Defined in lib/context/edit.js
rebuildBlock(block) function
Rebuild one content block per the module-header field policy.
block*
Returns object — a NEW block object
Defined in lib/context/edit.js
editMessage(context, i, newMessage) function
Replace context[i] with an edited message, rebuilt from recognized fields (stale provider/cache identifiers dropped). Mutates in place.
contextArray- caller-owned array
inumber- message index
newMessageobject- the edited message
Returns object — the stored (rebuilt) message
Defined in lib/context/edit.js
editBlock(context, i, j, newBlock) function
Replace context[i].content[j] with an edited block. The containing message is rebuilt as well (stale message-level identifiers dropped); other blocks are preserved through block rebuild.
contextArrayinumberjnumbernewBlockobject
Returns object — the stored (rebuilt) block
Defined in lib/context/edit.js
rollbackTo(context, i) function
Roll back to index i: remove messages at index >= i. Mutates in place. Valid targets are exactly the existing indexes 0..length-1 — passing the count is out of range (never a silent no-op).
contextArrayinumber
Returns Array — the removed messages
Defined in lib/context/edit.js
pop(context) function
Remove and return the last message. Mutates in place.
contextArray
Returns object|undefined — the removed message
Defined in lib/context/edit.js
removeMessages(context, indexes) function
Remove selected message indexes and return them in source order.
Defined in lib/context/edit.js
TOKENS_PER_WORD = 4 / 3 constant
tokens ≈ words × 4/3 (token-per-word likelihood ratio)
Defined in lib/context/usage.js
wordCount(text) function
@returns {number} whitespace-separated words
textstring- @returns {number} whitespace-separated words
Defined in lib/context/usage.js
estimateTokens(text) function
@returns {number} estimated token count
textstring- @returns {number} estimated token count
Defined in lib/context/usage.js
estimateContextTokens(context = []) function
Estimated token count of a whole context (the input side of a request — also the live "window consumption" readout when no provider-reported count exists yet). Counts words per block: the historical one-giant-string + word-array version allocated several full copies of the context per call, per frame.
[context]Array
Returns number
Defined in lib/context/usage.js
estimateUsage(context = [], message) function
Estimate usage from the request context and the assembled response.
[context]Array- request messages (input side)
[message]object- assembled assistant message (output side)
Returns {inputTokens:number, outputTokens:number, source:"estimate"}
Defined in lib/context/usage.js
finalizeUsage(reported, context, message) function
Normalize provider-reported usage, or fall back to estimation. Provider numbers win per-field only as a whole: a partial/invalid report is treated as absent (honest fallback, no mixed sources).
reported*- whatever the connector extracted
[context]Array- request context (fallback input side)
[message]object- assembled message (fallback output side)
Returns {inputTokens:number, outputTokens:number, source:string}
Defined in lib/context/usage.js
usageSummary(usage) function
One-line human-readable usage summary (e.g. for a host's diagnostics).
Defined in lib/context/usage.js