kestrel.markets
Version:
A typed, token-efficient language + runtime for agentic trading: agents author bounded plans, the runtime fires them at the tick. CLI + typed library + MCP server.
70 lines (69 loc) • 3.79 kB
JavaScript
/**
* Typed, LOUD errors for the IB Gateway TWS-socket transport (kestrel-7o2.5). A dropped socket,
* an auth/handshake failure, a lost heartbeat, or a misconfigured session is **never** a silent
* no-op — it surfaces here (AGENTS: fail-closed; ADR-0034). Secrets/credentials (the account id)
* are NEVER placed on an error message: any account echoed is redacted at the call site.
*
* These are the edge-adapter's own error types; they are distinct classes (not bare `Error`) so a
* caller can catch a connection loss specifically and reach STAND_DOWN, and can never mistake a
* transport failure for an unrelated one.
*/
/**
* A Kestrel identity could not be mapped onto exactly ONE broker contract (kestrel-7o2.6) — the
* LOUD, typed, fail-closed refusal that routes to STAND_DOWN. Thrown INSTEAD of returning a guessed
* contract: an ambiguous, unresolvable, or half-specified identity NEVER yields a contract.
*
* Carries the typed {@link IbkrContractFailure} kind, a human-legible {@link reason} (already
* secret-free — the account is redacted at the call site, as the transport redacts it), the IB
* {@link code} when the venue named one, and — for `ambiguous` — how many candidates the gateway
* returned, so the log says *how* ambiguous without ever naming the arbitrary winner (there is none).
*/
export class IbkrContractError extends Error {
name = "IbkrContractError";
failure;
/** The secret-free reason, logged verbatim on the STAND_DOWN path. */
reason;
/** The underlying IB error code, when the venue named one (e.g. 200 "no security definition"). */
code;
/** How many definitions the gateway matched. `0` for unresolvable, `>1` for ambiguous. */
candidates;
constructor(failure, reason,
// `| undefined` is explicit for `exactOptionalPropertyTypes`: a caller forwarding an
// already-`number | undefined` code/candidate count must still typecheck.
options = {}) {
super(`IBKR contract resolution refused [${failure}]: ${reason} (fail-closed; STAND_DOWN)`, options.cause === undefined ? undefined : { cause: options.cause });
this.failure = failure;
this.reason = reason;
this.code = options.code;
this.candidates = options.candidates;
}
}
/** IB Gateway transport configuration is missing or inconsistent (fail-closed; no baked endpoint,
* so an unresolved host/port surfaces here rather than defaulting silently to a wrong venue). */
export class IbkrConfigError extends Error {
name = "IbkrConfigError";
constructor(message, options = {}) {
super(message, options.cause === undefined ? undefined : { cause: options.cause });
}
}
/**
* The IB Gateway socket connection failed, dropped, lost its heartbeat, or failed to authenticate
* (kestrel-7o2.5). Thrown on USE of a transport that is not connected or has gone degraded, and
* used to REJECT a `connect()` that never completed its handshake. Carries the typed
* {@link IbkrFailure} kind and the underlying IB {@link ErrorCode} (a number) when one is known, so
* the caller can log the exact wall and STAND_DOWN. NEVER carries a credential/account.
*/
export class IbkrConnectionError extends Error {
name = "IbkrConnectionError";
failure;
/** The underlying IB `ErrorCode` (numeric) when the failure originated from a TWS error event. */
code;
constructor(failure, message,
// `| undefined` is explicit: under `exactOptionalPropertyTypes` a caller forwarding an
// already-`number | undefined` code (a latched failure being rethrown) must still typecheck.
options = {}) {
super(message, options.cause === undefined ? undefined : { cause: options.cause });
this.failure = failure;
this.code = options.code;
}
}