@corbits/system-one 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,193 @@
1
+ import { type } from "arktype";
2
+ import { BEARER_CREDENTIAL_SENTINEL, ProtocolMismatchError, } from "@intx/inference";
3
+ import { resolveEndpoint } from "./config.js";
4
+ import { Decision, toDecision, toWireQuestions, WireResponseBody, QuestionList, State, } from "./schemas.js";
5
+ // ---------------------------------------------------------------------------
6
+ // Adapter
7
+ // ---------------------------------------------------------------------------
8
+ //
9
+ // A thin Interchange `ProviderAdapter` bridge over the Jev evaluate wire
10
+ // protocol (`evaluate()`'s contract: state + questions in, decisions out).
11
+ // `buildRequest` encodes the conversation transcript as the evaluation
12
+ // state; a caller that already has Jev-shaped payloads passes them per call
13
+ // through `providerOptions.systemOne` (`{ state?, questions? }`), validated
14
+ // here with arktype. Decisions come back as `inference.text.delta` events
15
+ // carrying each decision's JSON, followed by an `inference.usage` event —
16
+ // populated from the response's `usage` block when the backend reports one.
17
+ // Auth never touches key material here: the request carries the bearer
18
+ // sentinel and the host's harness injects the real credential.
19
+ /** Provider id this package serves. */
20
+ export const SYSTEM_ONE_PROVIDER = "corbits-system-one";
21
+ // Per-call Jev payload overrides via `InferenceOptions.providerOptions`.
22
+ // `state` replaces the transcript-derived default; `questions` replaces the
23
+ // single-question default. Both are validated, never cast — `QuestionList`
24
+ // carries the same non-empty/unique-id contract as `EvaluateInput`.
25
+ const SystemOneProviderOptions = type({
26
+ "state?": State,
27
+ "questions?": QuestionList,
28
+ "+": "reject",
29
+ });
30
+ // The Jev evaluate response body is the shared `WireResponseBody` envelope
31
+ // (see schemas.ts): answers arrive in an id-keyed map with per-kind shapes.
32
+ // Extra backend fields validate but are never echoed: `toDecision` builds
33
+ // clean decisions, so they never become false protocol mismatches nor echoed
34
+ // tokens.
35
+ const EMPTY_PARTIAL = { text: "" };
36
+ const ZERO_USAGE = {
37
+ input: 0,
38
+ output: 0,
39
+ cacheRead: 0,
40
+ cacheWrite: 0,
41
+ thinking: 0,
42
+ };
43
+ // The bridge default question, used when the caller supplies no questions
44
+ // via `providerOptions.systemOne`: a conversation has no inherent Jev
45
+ // questions, so the adapter asks the one boolean every transcript answers —
46
+ // whether the turn responds — and lets the host interpret the decision.
47
+ const DEFAULT_QUESTIONS = [
48
+ {
49
+ type: "boolean",
50
+ id: "response",
51
+ instructions: "Does this turn respond to the conversation?",
52
+ },
53
+ ];
54
+ function transcriptText(turns) {
55
+ const texts = [];
56
+ for (const turn of turns) {
57
+ const parts = [];
58
+ const content = turn.content;
59
+ for (const block of content) {
60
+ if (block.type === "text")
61
+ parts.push(block.text);
62
+ }
63
+ if (parts.length > 0)
64
+ texts.push(`${turn.role}: ${parts.join("")}`);
65
+ }
66
+ return texts.join("\n");
67
+ }
68
+ function toTokenUsage(usage) {
69
+ if (usage === undefined)
70
+ return ZERO_USAGE;
71
+ return {
72
+ input: usage.input_tokens,
73
+ output: usage.output_tokens,
74
+ cacheRead: 0,
75
+ cacheWrite: 0,
76
+ thinking: 0,
77
+ };
78
+ }
79
+ function parseDecisions(body, provider) {
80
+ let parsed;
81
+ try {
82
+ parsed = JSON.parse(body);
83
+ }
84
+ catch (cause) {
85
+ throw new ProtocolMismatchError(`${provider} parseJSONResponse: malformed JSON response body: ${cause instanceof Error ? cause.message : String(cause)}`, body);
86
+ }
87
+ const envelope = WireResponseBody(parsed);
88
+ if (envelope instanceof type.errors) {
89
+ throw new ProtocolMismatchError(`${provider} parseJSONResponse: response failed schema validation: ${envelope.summary}`, parsed);
90
+ }
91
+ const decisions = Object.keys(envelope.answers).map((id) => {
92
+ const answer = envelope.answers[id];
93
+ if (answer === undefined) {
94
+ throw new ProtocolMismatchError(`${provider} parseJSONResponse: answer id "${id}" vanished during parsing`, parsed);
95
+ }
96
+ try {
97
+ return toDecision(id, answer);
98
+ }
99
+ catch (cause) {
100
+ throw new ProtocolMismatchError(`${provider} parseJSONResponse: ${cause instanceof Error ? cause.message : String(cause)}`, parsed);
101
+ }
102
+ });
103
+ return { decisions, usage: envelope.usage };
104
+ }
105
+ /**
106
+ * Builds the Interchange `ProviderAdapter` for System One against the
107
+ * host's single copy of `@intx/inference` (peer dependency, never vendored).
108
+ * The optional `config` pins the endpoint (official by default, gateway, or
109
+ * a custom URL) and the per-call model default; the inference call's own
110
+ * `model` argument wins for the request body.
111
+ */
112
+ export function createSystemOneAdapter(config) {
113
+ const endpoint = resolveEndpoint(config?.endpoint);
114
+ const source = {
115
+ sourceId: SYSTEM_ONE_PROVIDER,
116
+ provider: SYSTEM_ONE_PROVIDER,
117
+ model: endpoint.model ?? "unknown",
118
+ };
119
+ const buildRequest = (messages, model, options) => {
120
+ let state = { transcript: transcriptText(messages) };
121
+ let questions = DEFAULT_QUESTIONS;
122
+ const rawOverrides = options.providerOptions?.["systemOne"];
123
+ if (rawOverrides !== undefined) {
124
+ const overrides = SystemOneProviderOptions(rawOverrides);
125
+ if (overrides instanceof type.errors) {
126
+ throw new ProtocolMismatchError(`${SYSTEM_ONE_PROVIDER} buildRequest: invalid providerOptions.systemOne: ${overrides.summary}`, rawOverrides);
127
+ }
128
+ if (overrides.state !== undefined)
129
+ state = overrides.state;
130
+ if (overrides.questions !== undefined)
131
+ questions = overrides.questions;
132
+ }
133
+ const requestModel = model || endpoint.model || "unknown";
134
+ source.model = requestModel;
135
+ const headers = {
136
+ "content-type": "application/json",
137
+ accept: "application/json",
138
+ authorization: BEARER_CREDENTIAL_SENTINEL,
139
+ };
140
+ return {
141
+ url: endpoint.url,
142
+ headers,
143
+ body: JSON.stringify({
144
+ state,
145
+ questions: toWireQuestions(questions),
146
+ model: requestModel,
147
+ }),
148
+ };
149
+ };
150
+ const parseJSONResponse = (responseBody) => {
151
+ const { decisions, usage } = parseDecisions(responseBody, SYSTEM_ONE_PROVIDER);
152
+ const events = [];
153
+ let index = 0;
154
+ for (const decision of decisions) {
155
+ const token = JSON.stringify(decision);
156
+ events.push({
157
+ type: "inference.text.delta",
158
+ seq: 0,
159
+ data: { token, partial: EMPTY_PARTIAL, index },
160
+ });
161
+ index += 1;
162
+ }
163
+ events.push({
164
+ type: "inference.usage",
165
+ seq: 0,
166
+ data: { usage: toTokenUsage(usage), source: { ...source } },
167
+ });
168
+ return events;
169
+ };
170
+ // The Jev evaluate protocol is non-streaming: a streaming chunk is just a
171
+ // complete body arriving early, so the SSE path decodes the same JSON.
172
+ const parseResponse = (sseData) => parseJSONResponse(sseData);
173
+ // Jev answers 429/529 with a `retry-after` header; surfacing it lets the
174
+ // host harness's retry policy honor the backend's own backoff hint.
175
+ const extractRetryAfterMs = (headers) => {
176
+ const raw = headers.get("retry-after");
177
+ if (raw === null)
178
+ return undefined;
179
+ const seconds = Number(raw);
180
+ if (Number.isFinite(seconds) && seconds >= 0)
181
+ return seconds * 1000;
182
+ const at = Date.parse(raw);
183
+ if (!Number.isNaN(at))
184
+ return Math.max(0, at - Date.now());
185
+ return undefined;
186
+ };
187
+ return {
188
+ buildRequest,
189
+ parseResponse,
190
+ parseJSONResponse,
191
+ extractRetryAfterMs,
192
+ };
193
+ }
@@ -0,0 +1,21 @@
1
+ /** Options for one evaluation POST: timeout and auth, resolved by `evaluate`. */
2
+ export type PostEvaluateOptions = {
3
+ timeoutMs?: number;
4
+ apiKey?: string;
5
+ };
6
+ /** The decoded JSON body of a 2xx evaluation response, with its latency. */
7
+ export type PostEvaluateResponse = {
8
+ data: unknown;
9
+ latencyMs: number;
10
+ httpStatus: number;
11
+ };
12
+ /**
13
+ * POSTs an evaluation payload and returns the decoded JSON body. Sends
14
+ * `Authorization: Bearer <apiKey>` only when a key is present; aborts the
15
+ * exchange when `timeoutMs` elapses. A `timeoutMs` that is not a finite
16
+ * number >= 0 falls back to `DEFAULT_TIMEOUT_MS`. Throws `TimeoutError` on
17
+ * timeout, `HttpError` (status only, never the body) on non-2xx, and
18
+ * `NetworkError` when no HTTP exchange completes or the 2xx body is not
19
+ * valid JSON.
20
+ */
21
+ export declare function postEvaluate(url: string, body: unknown, options: PostEvaluateOptions): Promise<PostEvaluateResponse>;
package/dist/client.js ADDED
@@ -0,0 +1,67 @@
1
+ import { DEFAULT_TIMEOUT_MS } from "./config.js";
2
+ import { HttpError, NetworkError, SystemOneError, TimeoutError, } from "./errors.js";
3
+ /**
4
+ * POSTs an evaluation payload and returns the decoded JSON body. Sends
5
+ * `Authorization: Bearer <apiKey>` only when a key is present; aborts the
6
+ * exchange when `timeoutMs` elapses. A `timeoutMs` that is not a finite
7
+ * number >= 0 falls back to `DEFAULT_TIMEOUT_MS`. Throws `TimeoutError` on
8
+ * timeout, `HttpError` (status only, never the body) on non-2xx, and
9
+ * `NetworkError` when no HTTP exchange completes or the 2xx body is not
10
+ * valid JSON.
11
+ */
12
+ export async function postEvaluate(url, body, options) {
13
+ let serialized;
14
+ try {
15
+ serialized = JSON.stringify(body);
16
+ }
17
+ catch {
18
+ throw new SystemOneError("parse-error", "postEvaluate: request body is not JSON-serializable");
19
+ }
20
+ const rawTimeoutMs = options.timeoutMs;
21
+ const timeoutMs = rawTimeoutMs !== undefined &&
22
+ Number.isFinite(rawTimeoutMs) &&
23
+ rawTimeoutMs >= 0
24
+ ? rawTimeoutMs
25
+ : DEFAULT_TIMEOUT_MS;
26
+ const controller = new AbortController();
27
+ const timer = setTimeout(() => {
28
+ controller.abort();
29
+ }, timeoutMs);
30
+ const start = Date.now();
31
+ try {
32
+ const headers = {
33
+ "content-type": "application/json",
34
+ accept: "application/json",
35
+ };
36
+ if (options.apiKey !== undefined && options.apiKey !== "") {
37
+ headers["authorization"] = `Bearer ${options.apiKey}`;
38
+ }
39
+ let res;
40
+ try {
41
+ res = await fetch(url, {
42
+ method: "POST",
43
+ headers,
44
+ body: serialized,
45
+ signal: controller.signal,
46
+ });
47
+ }
48
+ catch (cause) {
49
+ if (controller.signal.aborted)
50
+ throw new TimeoutError(timeoutMs);
51
+ throw new NetworkError(`system-one request failed: ${cause instanceof Error ? cause.message : String(cause)}`);
52
+ }
53
+ if (!res.ok)
54
+ throw new HttpError(res.status);
55
+ let data;
56
+ try {
57
+ data = await res.json();
58
+ }
59
+ catch {
60
+ throw new NetworkError("system-one response body is not valid JSON");
61
+ }
62
+ return { data, latencyMs: Date.now() - start, httpStatus: res.status };
63
+ }
64
+ finally {
65
+ clearTimeout(timer);
66
+ }
67
+ }
@@ -0,0 +1,36 @@
1
+ import type { EndpointConfig } from "./schemas.js";
2
+ export declare const SystemOneQuirks: import("arktype/internal/variants/object.ts").ObjectType<{
3
+ baseUrl?: string;
4
+ model?: string;
5
+ }, {}>;
6
+ export type SystemOneQuirks = typeof SystemOneQuirks.infer;
7
+ export declare const SYSTEM_ONE_DEFAULT_QUIRKS: SystemOneQuirks;
8
+ export declare const GATEWAY_QUIRKS: SystemOneQuirks;
9
+ export declare const TYPESAFE_API_KEY_ENV = "TYPESAFE_API_KEY";
10
+ export declare const GATEWAY_API_KEY_ENV = "AI_GATEWAY_API_KEY";
11
+ export declare const GATEWAY_OIDC_ENV = "VERCEL_OIDC_TOKEN";
12
+ export declare const SYSTEM_ONE_API_KEY_ENV = "SYSTEM_ONE_API_KEY";
13
+ /**
14
+ * Default bound for one evaluation round trip in milliseconds. 1500ms: a
15
+ * single non-streaming POST over an already-warm connection should answer
16
+ * far inside a second, and there is no published pilot SLO to calibrate
17
+ * against yet — so the default fails fast to a typed `FallbackResult`
18
+ * instead of holding the caller's round trip hostage. Callers with slower
19
+ * backends (or a custom endpoint across regions) set `timeoutMs` per call.
20
+ */
21
+ export declare const DEFAULT_TIMEOUT_MS = 1500;
22
+ /** One resolved evaluation target: the URL to POST, the model to send. */
23
+ export type ResolvedEndpoint = {
24
+ url: string;
25
+ backend: "corbits-system-one" | "gateway" | "custom";
26
+ model?: string;
27
+ };
28
+ /**
29
+ * Resolves an evaluation endpoint to a concrete POST target. A per-call
30
+ * `endpoint` wins over the package default (`official`); `custom` must
31
+ * carry its own `url` and throws a typed `SystemOneError` when it does
32
+ * not. A `custom` target keeps the `'custom'` backend label so telemetry
33
+ * distinguishes caller-routed traffic from the official endpoint —
34
+ * `'gateway'` is reserved for the proxy quirks path.
35
+ */
36
+ export declare function resolveEndpoint(endpoint?: EndpointConfig): ResolvedEndpoint;
package/dist/config.js ADDED
@@ -0,0 +1,88 @@
1
+ import { type } from "arktype";
2
+ import { SystemOneError } from "./errors.js";
3
+ // ---------------------------------------------------------------------------
4
+ // Quirks
5
+ // ---------------------------------------------------------------------------
6
+ //
7
+ // Everything one System One backend needs to bend the shared evaluation wire
8
+ // protocol to its own endpoint, expressed as data instead of a fork of the
9
+ // client. Every field here must be JSON-safe: quirks ride inside persisted
10
+ // configuration, so a function-valued field would silently fail to survive
11
+ // that round trip.
12
+ // Per-endpoint accommodations for the System One evaluation protocol. Every
13
+ // field is optional; an absent field resolves to the protocol default, so a
14
+ // caller that supplies no quirks gets no accommodation.
15
+ export const SystemOneQuirks = type({
16
+ "baseUrl?": "string",
17
+ "model?": "string",
18
+ "+": "reject",
19
+ });
20
+ // The official System One endpoint: the documented Jev systemone route with
21
+ // the stable model alias. Callers needing the proxied route use `gateway`;
22
+ // callers with their own deployment use `custom` with an explicit `url`.
23
+ export const SYSTEM_ONE_DEFAULT_QUIRKS = {
24
+ baseUrl: "https://api.typesafe.ai/v1/systemone",
25
+ model: "jev-latest",
26
+ };
27
+ // The Vercel AI Gateway proxy for the Jev model, TypeSafe-compatible REST
28
+ // shape. Callers select it per call with `endpoint: { kind: "gateway" }`.
29
+ export const GATEWAY_QUIRKS = {
30
+ baseUrl: "https://ai-gateway.vercel.sh/typesafe/v1/systemone",
31
+ model: "typesafe-ai/jev",
32
+ };
33
+ // Credential sources, one per endpoint: a TypeSafe key never authenticates
34
+ // to the gateway and a gateway key never authenticates to TypeSafe direct,
35
+ // so each endpoint reads its own names. `SYSTEM_ONE_API_KEY` stays as the
36
+ // legacy universal fallback (and the key for `custom` endpoints).
37
+ export const TYPESAFE_API_KEY_ENV = "TYPESAFE_API_KEY";
38
+ export const GATEWAY_API_KEY_ENV = "AI_GATEWAY_API_KEY";
39
+ export const GATEWAY_OIDC_ENV = "VERCEL_OIDC_TOKEN";
40
+ export const SYSTEM_ONE_API_KEY_ENV = "SYSTEM_ONE_API_KEY";
41
+ // ---------------------------------------------------------------------------
42
+ // Edge defaults and endpoint resolution
43
+ // ---------------------------------------------------------------------------
44
+ //
45
+ // Defaults resolve here, at the `evaluate` edge, never inside a schema:
46
+ // schemas parse, they don't fill in defaults.
47
+ /**
48
+ * Default bound for one evaluation round trip in milliseconds. 1500ms: a
49
+ * single non-streaming POST over an already-warm connection should answer
50
+ * far inside a second, and there is no published pilot SLO to calibrate
51
+ * against yet — so the default fails fast to a typed `FallbackResult`
52
+ * instead of holding the caller's round trip hostage. Callers with slower
53
+ * backends (or a custom endpoint across regions) set `timeoutMs` per call.
54
+ */
55
+ export const DEFAULT_TIMEOUT_MS = 1500;
56
+ /**
57
+ * Resolves an evaluation endpoint to a concrete POST target. A per-call
58
+ * `endpoint` wins over the package default (`official`); `custom` must
59
+ * carry its own `url` and throws a typed `SystemOneError` when it does
60
+ * not. A `custom` target keeps the `'custom'` backend label so telemetry
61
+ * distinguishes caller-routed traffic from the official endpoint —
62
+ * `'gateway'` is reserved for the proxy quirks path.
63
+ */
64
+ export function resolveEndpoint(endpoint) {
65
+ if (endpoint?.kind === "custom") {
66
+ if (endpoint.url === "") {
67
+ throw new SystemOneError("config-error", 'evaluate: endpoint kind "custom" requires an explicit url');
68
+ }
69
+ const resolved = { url: endpoint.url, backend: "custom" };
70
+ if (endpoint.model !== undefined)
71
+ resolved.model = endpoint.model;
72
+ return resolved;
73
+ }
74
+ const kind = endpoint?.kind ?? "official";
75
+ const quirks = kind === "gateway" ? GATEWAY_QUIRKS : SYSTEM_ONE_DEFAULT_QUIRKS;
76
+ const url = quirks.baseUrl;
77
+ if (url === undefined || url === "") {
78
+ throw new SystemOneError("backend-unreachable", `evaluate: no baseUrl configured for endpoint kind "${kind}"`);
79
+ }
80
+ const resolved = {
81
+ url,
82
+ backend: kind === "gateway" ? "gateway" : "corbits-system-one",
83
+ };
84
+ const model = endpoint?.model ?? quirks.model;
85
+ if (model !== undefined)
86
+ resolved.model = model;
87
+ return resolved;
88
+ }
@@ -0,0 +1,35 @@
1
+ import type { FallbackReason } from "./schemas.js";
2
+ /** Every error code `evaluate` can throw. Thrown-only codes (`"not-implemented"`, `"config-error"`) never appear as fallback reasons. */
3
+ export type SystemOneErrorCode = FallbackReason | "not-implemented" | "config-error";
4
+ /** Typed error thrown when `evaluate` cannot return a result at all. */
5
+ export declare class SystemOneError extends Error {
6
+ readonly code: SystemOneErrorCode;
7
+ constructor(code: SystemOneErrorCode, message: string);
8
+ }
9
+ /**
10
+ * The evaluation POST exceeded its timeout budget. Thrown by `postEvaluate`;
11
+ * `evaluate` reports it as a `FallbackResult` with reason `'timeout'`.
12
+ */
13
+ export declare class TimeoutError extends SystemOneError {
14
+ readonly timeoutMs: number;
15
+ constructor(timeoutMs: number);
16
+ }
17
+ /**
18
+ * The evaluation POST never completed an HTTP exchange (DNS/TLS failure,
19
+ * refused connection, reset stream) or the 200 body was not valid JSON.
20
+ * Thrown by `postEvaluate`; `evaluate` reports it as a `FallbackResult`
21
+ * with reason `'network'`.
22
+ */
23
+ export declare class NetworkError extends SystemOneError {
24
+ constructor(message: string);
25
+ }
26
+ /**
27
+ * The evaluation POST completed with a non-2xx status. Carries the status
28
+ * only — never the response body, which is untrusted vendor output.
29
+ * Thrown by `postEvaluate`; `evaluate` reports it as a `FallbackResult`
30
+ * with reason `'http-error'`.
31
+ */
32
+ export declare class HttpError extends SystemOneError {
33
+ readonly httpStatus: number;
34
+ constructor(httpStatus: number);
35
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,47 @@
1
+ /** Typed error thrown when `evaluate` cannot return a result at all. */
2
+ export class SystemOneError extends Error {
3
+ code;
4
+ constructor(code, message) {
5
+ super(message);
6
+ this.name = "SystemOneError";
7
+ this.code = code;
8
+ }
9
+ }
10
+ /**
11
+ * The evaluation POST exceeded its timeout budget. Thrown by `postEvaluate`;
12
+ * `evaluate` reports it as a `FallbackResult` with reason `'timeout'`.
13
+ */
14
+ export class TimeoutError extends SystemOneError {
15
+ timeoutMs;
16
+ constructor(timeoutMs) {
17
+ super("timeout", `system-one request timed out after ${timeoutMs}ms`);
18
+ this.name = "TimeoutError";
19
+ this.timeoutMs = timeoutMs;
20
+ }
21
+ }
22
+ /**
23
+ * The evaluation POST never completed an HTTP exchange (DNS/TLS failure,
24
+ * refused connection, reset stream) or the 200 body was not valid JSON.
25
+ * Thrown by `postEvaluate`; `evaluate` reports it as a `FallbackResult`
26
+ * with reason `'network'`.
27
+ */
28
+ export class NetworkError extends SystemOneError {
29
+ constructor(message) {
30
+ super("network", message);
31
+ this.name = "NetworkError";
32
+ }
33
+ }
34
+ /**
35
+ * The evaluation POST completed with a non-2xx status. Carries the status
36
+ * only — never the response body, which is untrusted vendor output.
37
+ * Thrown by `postEvaluate`; `evaluate` reports it as a `FallbackResult`
38
+ * with reason `'http-error'`.
39
+ */
40
+ export class HttpError extends SystemOneError {
41
+ httpStatus;
42
+ constructor(httpStatus) {
43
+ super("http-error", `system-one request failed with HTTP ${httpStatus}`);
44
+ this.name = "HttpError";
45
+ this.httpStatus = httpStatus;
46
+ }
47
+ }
@@ -0,0 +1,18 @@
1
+ import { EvaluateInput, type EvaluateResult, type FallbackResult } from "./schemas.js";
2
+ /**
3
+ * Runs one typed-decision evaluation against System One (or its gateway)
4
+ * and returns either the backend's decisions or a typed fallback. One POST
5
+ * per call no matter how many questions are asked. Credential precedence:
6
+ * a non-empty per-call `apiKey` (an empty string falls through to the
7
+ * environment, never shadowing it), then the endpoint's environment key —
8
+ * `TYPESAFE_API_KEY` for official, `AI_GATEWAY_API_KEY` then
9
+ * `VERCEL_OIDC_TOKEN` for gateway — then the legacy `SYSTEM_ONE_API_KEY`
10
+ * fallback, then a fail-closed `'no-key'` fallback with zero fetch calls.
11
+ * A `timeoutMs` that is not a finite number >= 0 falls back to
12
+ * `DEFAULT_TIMEOUT_MS`. Transport failures map to matching fallback reasons
13
+ * (`'timeout'`, `'network'`, `'http-error'`); backend output that fails
14
+ * strict validation maps to `'parse-error'` with the violation in `detail`.
15
+ * Only caller-side misuse (invalid input, a `custom` endpoint without a
16
+ * `url`) throws, as a typed `SystemOneError`.
17
+ */
18
+ export declare function evaluate(input: EvaluateInput): Promise<EvaluateResult | FallbackResult>;