@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.
- package/LICENSE +176 -0
- package/README.md +279 -0
- package/dist/adapter.d.ts +12 -0
- package/dist/adapter.js +193 -0
- package/dist/client.d.ts +21 -0
- package/dist/client.js +67 -0
- package/dist/config.d.ts +36 -0
- package/dist/config.js +88 -0
- package/dist/errors.d.ts +35 -0
- package/dist/errors.js +47 -0
- package/dist/evaluate.d.ts +18 -0
- package/dist/evaluate.js +346 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +7 -0
- package/dist/schemas.d.ts +444 -0
- package/dist/schemas.js +311 -0
- package/dist/telemetry.d.ts +24 -0
- package/dist/telemetry.js +51 -0
- package/package.json +64 -0
package/dist/evaluate.js
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { type } from "arktype";
|
|
2
|
+
import { postEvaluate } from "./client.js";
|
|
3
|
+
import { DEFAULT_TIMEOUT_MS, GATEWAY_API_KEY_ENV, GATEWAY_OIDC_ENV, resolveEndpoint, SYSTEM_ONE_API_KEY_ENV, TYPESAFE_API_KEY_ENV, } from "./config.js";
|
|
4
|
+
import { HttpError, NetworkError, SystemOneError, TimeoutError, } from "./errors.js";
|
|
5
|
+
import { APPROXIMATE_SUM_TOLERANCE as SUM_TOLERANCE, EvaluateInput, toDecision, toWireQuestions, WireRequest, WireResponseBody, } from "./schemas.js";
|
|
6
|
+
import { recordTelemetryEvent, } from "./telemetry.js";
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// evaluate
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
//
|
|
11
|
+
// One typed-decision evaluation: validate the caller input, resolve the
|
|
12
|
+
// endpoint and credentials, POST state + questions once, and strictly
|
|
13
|
+
// validate the backend's answers against the submitted questions. Anything
|
|
14
|
+
// the backend gets wrong — and every transport failure — comes back as a
|
|
15
|
+
// typed `FallbackResult`, never a throw and never raw vendor JSON.
|
|
16
|
+
//
|
|
17
|
+
// Wire notes (live Jev contract): questions serialize to an id-keyed map,
|
|
18
|
+
// the `boolean` alias maps to native `noul`, the top-level `model` is always
|
|
19
|
+
// sent, and answers arrive in an `answers` map keyed by the same ids.
|
|
20
|
+
// Collects secrets out of raw caller input so input-validation errors can
|
|
21
|
+
// scrub them from the arktype summary before throwing. Key material must
|
|
22
|
+
// never appear in an error message — and neither may credentials embedded in
|
|
23
|
+
// a custom endpoint URL (`https://user:pass@host/...` echoes into the
|
|
24
|
+
// summary verbatim, so the userinfo fragments are scrubbed too).
|
|
25
|
+
function secretsIn(raw) {
|
|
26
|
+
if (typeof raw !== "object" || raw === null)
|
|
27
|
+
return [];
|
|
28
|
+
if (!("config" in raw))
|
|
29
|
+
return [];
|
|
30
|
+
const config = raw.config;
|
|
31
|
+
if (typeof config !== "object" || config === null)
|
|
32
|
+
return [];
|
|
33
|
+
const secrets = [];
|
|
34
|
+
if ("apiKey" in config) {
|
|
35
|
+
const key = config.apiKey;
|
|
36
|
+
if (typeof key === "string" && key !== "")
|
|
37
|
+
secrets.push(key);
|
|
38
|
+
}
|
|
39
|
+
if ("endpoint" in config) {
|
|
40
|
+
const endpoint = config.endpoint;
|
|
41
|
+
if (typeof endpoint === "object" &&
|
|
42
|
+
endpoint !== null &&
|
|
43
|
+
"url" in endpoint) {
|
|
44
|
+
const url = endpoint.url;
|
|
45
|
+
if (typeof url === "string" && url !== "") {
|
|
46
|
+
try {
|
|
47
|
+
const parsedUrl = new URL(url);
|
|
48
|
+
if (parsedUrl.username !== "")
|
|
49
|
+
secrets.push(parsedUrl.username);
|
|
50
|
+
if (parsedUrl.password !== "")
|
|
51
|
+
secrets.push(parsedUrl.password);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Not a parseable URL: only worth scrubbing when it looks
|
|
55
|
+
// credential-bearing (an `@` userinfo separator).
|
|
56
|
+
if (url.includes("@"))
|
|
57
|
+
secrets.push(url);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return secrets;
|
|
63
|
+
}
|
|
64
|
+
// A URL with any userinfo credentials removed — `backendAttempted` goes into
|
|
65
|
+
// `FallbackResult`, which callers log and forward, so a caller-supplied
|
|
66
|
+
// `https://user:pass@host/...` must not echo its credentials back out.
|
|
67
|
+
function sanitizeUrl(url) {
|
|
68
|
+
try {
|
|
69
|
+
const parsed = new URL(url);
|
|
70
|
+
if (parsed.username === "" && parsed.password === "")
|
|
71
|
+
return url;
|
|
72
|
+
parsed.username = "";
|
|
73
|
+
parsed.password = "";
|
|
74
|
+
return parsed.toString();
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return url.replace(/\/\/[^/@]+@/, "//");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Strict cross-validation of one backend answer against its submitted
|
|
81
|
+
// question, per the live contract: a noul answer must carry its `noul`
|
|
82
|
+
// probability (noul has no confidence); a choice answer must carry `choice`,
|
|
83
|
+
// `probabilities`, and `confidence`; a score answer must carry `score`,
|
|
84
|
+
// `legend`, `probabilities`, and `confidence`. Probability sums are
|
|
85
|
+
// approximate (backend rounds to two decimals), never exact. Returns the
|
|
86
|
+
// violation, if any.
|
|
87
|
+
function checkAnswer(question, id, answer) {
|
|
88
|
+
const expectedType = question.type === "boolean" ? "noul" : question.type;
|
|
89
|
+
if (answer.type !== expectedType) {
|
|
90
|
+
return `answer "${id}" type "${answer.type}" does not match question type "${question.type}"`;
|
|
91
|
+
}
|
|
92
|
+
if (answer.type === "noul") {
|
|
93
|
+
if (answer.noul === undefined)
|
|
94
|
+
return `answer "${id}" is missing noul`;
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
if (answer.confidence === undefined) {
|
|
98
|
+
return `answer "${id}" is missing confidence`;
|
|
99
|
+
}
|
|
100
|
+
if (question.type === "choice" && answer.type === "choice") {
|
|
101
|
+
if (answer.choice === undefined)
|
|
102
|
+
return `answer "${id}" is missing choice`;
|
|
103
|
+
if (!(answer.choice in question.criteria)) {
|
|
104
|
+
return `answer "${id}" illegal option ${JSON.stringify(answer.choice)}`;
|
|
105
|
+
}
|
|
106
|
+
return checkProbabilities(id, Object.keys(question.criteria), answer.probabilities);
|
|
107
|
+
}
|
|
108
|
+
if (question.type === "score" && answer.type === "score") {
|
|
109
|
+
const levels = question.criteria.length;
|
|
110
|
+
if (answer.score === undefined)
|
|
111
|
+
return `answer "${id}" is missing score`;
|
|
112
|
+
if (!Number.isFinite(answer.score) ||
|
|
113
|
+
answer.score < 0 ||
|
|
114
|
+
answer.score > levels - 1) {
|
|
115
|
+
return `answer "${id}" score ${String(answer.score)} outside [0, ${levels - 1}]`;
|
|
116
|
+
}
|
|
117
|
+
if (answer.legend === undefined)
|
|
118
|
+
return `answer "${id}" is missing legend`;
|
|
119
|
+
const expected = new Set(Array.from({ length: levels }, (_, index) => String(index)));
|
|
120
|
+
const actual = new Set(Object.keys(answer.legend));
|
|
121
|
+
if (expected.size !== actual.size ||
|
|
122
|
+
![...expected].every((key) => actual.has(key))) {
|
|
123
|
+
return `answer "${id}" legend keys ${JSON.stringify(Object.keys(answer.legend))} do not match ${levels} levels`;
|
|
124
|
+
}
|
|
125
|
+
return checkProbabilities(id, [...expected], answer.probabilities);
|
|
126
|
+
}
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
// The probability map must cover exactly the contract keys — every option or
|
|
130
|
+
// every level index — with an approximate sum of 1. Extra keys are a shape
|
|
131
|
+
// violation, not tolerated extras: they would echo into the caller's
|
|
132
|
+
// decision as if they were real outcomes.
|
|
133
|
+
function checkProbabilities(id, requiredKeys, probabilities) {
|
|
134
|
+
if (probabilities === undefined) {
|
|
135
|
+
return `answer "${id}" is missing probabilities`;
|
|
136
|
+
}
|
|
137
|
+
const actual = new Set(Object.keys(probabilities));
|
|
138
|
+
if (actual.size !== requiredKeys.length ||
|
|
139
|
+
!requiredKeys.every((key) => actual.has(key))) {
|
|
140
|
+
return `answer "${id}" probabilities keys ${JSON.stringify([...actual])} do not match ${JSON.stringify(requiredKeys)}`;
|
|
141
|
+
}
|
|
142
|
+
const sum = Object.values(probabilities).reduce((total, n) => total + n, 0);
|
|
143
|
+
if (Math.abs(sum - 1) > SUM_TOLERANCE) {
|
|
144
|
+
return `answer "${id}" probabilities sum to ${sum}, expected ~1`;
|
|
145
|
+
}
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
// Strict cross-validation of backend answers against the submitted
|
|
149
|
+
// questions: the answer key set must equal the submitted id set exactly (no
|
|
150
|
+
// unknowns, no drops — map keys are unique by construction), and each answer
|
|
151
|
+
// must satisfy its question. Returns the first violation, if any.
|
|
152
|
+
function checkAnswers(questions, answers) {
|
|
153
|
+
const byId = new Map();
|
|
154
|
+
for (const question of questions)
|
|
155
|
+
byId.set(question.id, question);
|
|
156
|
+
const keys = Object.keys(answers);
|
|
157
|
+
if (keys.length !== questions.length) {
|
|
158
|
+
return `expected ${questions.length} answers, got ${keys.length}`;
|
|
159
|
+
}
|
|
160
|
+
for (const id of keys) {
|
|
161
|
+
const question = byId.get(id);
|
|
162
|
+
if (question === undefined)
|
|
163
|
+
return `unknown answer id "${id}"`;
|
|
164
|
+
const answer = answers[id];
|
|
165
|
+
if (answer === undefined)
|
|
166
|
+
return `answer id "${id}" vanished during parsing`;
|
|
167
|
+
const violation = checkAnswer(question, id, answer);
|
|
168
|
+
if (violation !== undefined)
|
|
169
|
+
return violation;
|
|
170
|
+
}
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
function envKey(name) {
|
|
174
|
+
const value = process.env[name];
|
|
175
|
+
return value === undefined || value === "" ? undefined : value;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Runs one typed-decision evaluation against System One (or its gateway)
|
|
179
|
+
* and returns either the backend's decisions or a typed fallback. One POST
|
|
180
|
+
* per call no matter how many questions are asked. Credential precedence:
|
|
181
|
+
* a non-empty per-call `apiKey` (an empty string falls through to the
|
|
182
|
+
* environment, never shadowing it), then the endpoint's environment key —
|
|
183
|
+
* `TYPESAFE_API_KEY` for official, `AI_GATEWAY_API_KEY` then
|
|
184
|
+
* `VERCEL_OIDC_TOKEN` for gateway — then the legacy `SYSTEM_ONE_API_KEY`
|
|
185
|
+
* fallback, then a fail-closed `'no-key'` fallback with zero fetch calls.
|
|
186
|
+
* A `timeoutMs` that is not a finite number >= 0 falls back to
|
|
187
|
+
* `DEFAULT_TIMEOUT_MS`. Transport failures map to matching fallback reasons
|
|
188
|
+
* (`'timeout'`, `'network'`, `'http-error'`); backend output that fails
|
|
189
|
+
* strict validation maps to `'parse-error'` with the violation in `detail`.
|
|
190
|
+
* Only caller-side misuse (invalid input, a `custom` endpoint without a
|
|
191
|
+
* `url`) throws, as a typed `SystemOneError`.
|
|
192
|
+
*/
|
|
193
|
+
export async function evaluate(input) {
|
|
194
|
+
const start = Date.now();
|
|
195
|
+
const parsed = EvaluateInput(input);
|
|
196
|
+
if (parsed instanceof type.errors) {
|
|
197
|
+
let summary = parsed.summary;
|
|
198
|
+
for (const secret of secretsIn(input)) {
|
|
199
|
+
summary = summary.split(secret).join("[redacted]");
|
|
200
|
+
}
|
|
201
|
+
throw new SystemOneError("parse-error", `evaluate: invalid input: ${summary}`);
|
|
202
|
+
}
|
|
203
|
+
const endpoint = resolveEndpoint(parsed.config?.endpoint);
|
|
204
|
+
const backendAttempted = sanitizeUrl(endpoint.url);
|
|
205
|
+
const rawTimeoutMs = parsed.config?.timeoutMs;
|
|
206
|
+
const timeoutMs = typeof rawTimeoutMs === "number" &&
|
|
207
|
+
Number.isFinite(rawTimeoutMs) &&
|
|
208
|
+
rawTimeoutMs >= 0
|
|
209
|
+
? rawTimeoutMs
|
|
210
|
+
: DEFAULT_TIMEOUT_MS;
|
|
211
|
+
const rawApiKey = parsed.config?.apiKey;
|
|
212
|
+
let apiKey;
|
|
213
|
+
let keySources;
|
|
214
|
+
if (rawApiKey !== undefined && rawApiKey !== "") {
|
|
215
|
+
apiKey = rawApiKey;
|
|
216
|
+
keySources = "config.apiKey";
|
|
217
|
+
}
|
|
218
|
+
else if (endpoint.backend === "corbits-system-one") {
|
|
219
|
+
apiKey = envKey(TYPESAFE_API_KEY_ENV) ?? envKey(SYSTEM_ONE_API_KEY_ENV);
|
|
220
|
+
keySources = `${TYPESAFE_API_KEY_ENV} or ${SYSTEM_ONE_API_KEY_ENV}`;
|
|
221
|
+
}
|
|
222
|
+
else if (endpoint.backend === "gateway") {
|
|
223
|
+
apiKey =
|
|
224
|
+
envKey(GATEWAY_API_KEY_ENV) ??
|
|
225
|
+
envKey(GATEWAY_OIDC_ENV) ??
|
|
226
|
+
envKey(SYSTEM_ONE_API_KEY_ENV);
|
|
227
|
+
keySources = `${GATEWAY_API_KEY_ENV}, ${GATEWAY_OIDC_ENV}, or ${SYSTEM_ONE_API_KEY_ENV}`;
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
apiKey = envKey(SYSTEM_ONE_API_KEY_ENV);
|
|
231
|
+
keySources = SYSTEM_ONE_API_KEY_ENV;
|
|
232
|
+
}
|
|
233
|
+
const model = endpoint.model ?? "typesafe-ai/jev";
|
|
234
|
+
const fallback = (reason, extra) => {
|
|
235
|
+
const result = {
|
|
236
|
+
fallback: true,
|
|
237
|
+
reason,
|
|
238
|
+
latencyMs: Date.now() - start,
|
|
239
|
+
backendAttempted,
|
|
240
|
+
};
|
|
241
|
+
if (extra?.httpStatus !== undefined)
|
|
242
|
+
result.httpStatus = extra.httpStatus;
|
|
243
|
+
if (extra?.detail !== undefined)
|
|
244
|
+
result.detail = extra.detail;
|
|
245
|
+
const event = {
|
|
246
|
+
event: "evaluate.fallback",
|
|
247
|
+
backend: endpoint.backend,
|
|
248
|
+
latencyMs: result.latencyMs,
|
|
249
|
+
reason,
|
|
250
|
+
modelId: model,
|
|
251
|
+
};
|
|
252
|
+
if (extra?.detail !== undefined)
|
|
253
|
+
event.detail = extra.detail;
|
|
254
|
+
recordTelemetryEvent(event);
|
|
255
|
+
return result;
|
|
256
|
+
};
|
|
257
|
+
const startEvent = {
|
|
258
|
+
event: "evaluate.start",
|
|
259
|
+
backend: endpoint.backend,
|
|
260
|
+
latencyMs: 0,
|
|
261
|
+
modelId: model,
|
|
262
|
+
};
|
|
263
|
+
recordTelemetryEvent(startEvent);
|
|
264
|
+
if (apiKey === undefined || apiKey === "") {
|
|
265
|
+
return fallback("no-key", {
|
|
266
|
+
detail: `no API key supplied; set config.apiKey or ${keySources}`,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
const wire = WireRequest({
|
|
270
|
+
model,
|
|
271
|
+
state: parsed.state,
|
|
272
|
+
questions: toWireQuestions(parsed.questions),
|
|
273
|
+
});
|
|
274
|
+
if (wire instanceof type.errors) {
|
|
275
|
+
throw new SystemOneError("parse-error", `evaluate: internal wire serialization failed: ${wire.summary}`);
|
|
276
|
+
}
|
|
277
|
+
let data;
|
|
278
|
+
let transportLatencyMs;
|
|
279
|
+
try {
|
|
280
|
+
const response = await postEvaluate(endpoint.url, wire, {
|
|
281
|
+
timeoutMs,
|
|
282
|
+
apiKey,
|
|
283
|
+
});
|
|
284
|
+
data = response.data;
|
|
285
|
+
transportLatencyMs = response.latencyMs;
|
|
286
|
+
}
|
|
287
|
+
catch (cause) {
|
|
288
|
+
if (cause instanceof HttpError) {
|
|
289
|
+
return fallback("http-error", { httpStatus: cause.httpStatus });
|
|
290
|
+
}
|
|
291
|
+
if (cause instanceof TimeoutError)
|
|
292
|
+
return fallback("timeout");
|
|
293
|
+
if (cause instanceof NetworkError)
|
|
294
|
+
return fallback("network");
|
|
295
|
+
throw cause;
|
|
296
|
+
}
|
|
297
|
+
const envelope = WireResponseBody(data);
|
|
298
|
+
if (envelope instanceof type.errors) {
|
|
299
|
+
return fallback("parse-error", {
|
|
300
|
+
detail: `response failed schema validation: ${envelope.summary.slice(0, 240)}`,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
const violation = checkAnswers(parsed.questions, envelope.answers);
|
|
304
|
+
if (violation !== undefined) {
|
|
305
|
+
return fallback("parse-error", { detail: violation });
|
|
306
|
+
}
|
|
307
|
+
const modelId = envelope.model ?? model;
|
|
308
|
+
const decisions = [];
|
|
309
|
+
for (const question of parsed.questions) {
|
|
310
|
+
const answer = envelope.answers[question.id];
|
|
311
|
+
if (answer === undefined) {
|
|
312
|
+
return fallback("parse-error", {
|
|
313
|
+
detail: `answer "${question.id}" vanished during parsing`,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
try {
|
|
317
|
+
decisions.push(toDecision(question.id, answer));
|
|
318
|
+
}
|
|
319
|
+
catch (cause) {
|
|
320
|
+
return fallback("parse-error", {
|
|
321
|
+
detail: cause instanceof Error ? cause.message : String(cause),
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
const result = {
|
|
326
|
+
decisions,
|
|
327
|
+
modelId,
|
|
328
|
+
backend: endpoint.backend,
|
|
329
|
+
latencyMs: transportLatencyMs,
|
|
330
|
+
fallback: false,
|
|
331
|
+
};
|
|
332
|
+
if (envelope.usage !== undefined) {
|
|
333
|
+
result.usage = {
|
|
334
|
+
inputTokens: envelope.usage.input_tokens,
|
|
335
|
+
outputTokens: envelope.usage.output_tokens,
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
const successEvent = {
|
|
339
|
+
event: "evaluate.success",
|
|
340
|
+
backend: endpoint.backend,
|
|
341
|
+
latencyMs: result.latencyMs,
|
|
342
|
+
modelId,
|
|
343
|
+
};
|
|
344
|
+
recordTelemetryEvent(successEvent);
|
|
345
|
+
return result;
|
|
346
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { DEFAULT_TIMEOUT_MS, GATEWAY_API_KEY_ENV, GATEWAY_OIDC_ENV, GATEWAY_QUIRKS, SYSTEM_ONE_API_KEY_ENV, SYSTEM_ONE_DEFAULT_QUIRKS, SystemOneQuirks, TYPESAFE_API_KEY_ENV, } from "./config.js";
|
|
2
|
+
export { postEvaluate } from "./client.js";
|
|
3
|
+
export type { PostEvaluateOptions, PostEvaluateResponse } from "./client.js";
|
|
4
|
+
export { evaluate } from "./evaluate.js";
|
|
5
|
+
export { createSystemOneAdapter, SYSTEM_ONE_PROVIDER } from "./adapter.js";
|
|
6
|
+
export { HttpError, NetworkError, SystemOneError, TimeoutError, } from "./errors.js";
|
|
7
|
+
export type { SystemOneErrorCode } from "./errors.js";
|
|
8
|
+
export { drainTelemetryEvents, MAX_BUFFERED_TELEMETRY_EVENTS, recordTelemetryEvent, SystemOneTelemetryEvent, } from "./telemetry.js";
|
|
9
|
+
export { APPROXIMATE_SUM_TOLERANCE, BooleanQuestion, ChoiceQuestion, Confidence, Decision, Description, EndpointConfig, EvaluateConfig, EvaluateInput, EvaluateResult, EvaluateResponseBody, FallbackReason, FallbackResult, JsonRecord, NoulQuestion, ProbabilityMap, Question, QuestionList, ScoreQuestion, State, toDecision, toWireQuestions, Usage, WireAnswer, WireQuestion, WireRequest, WireResponseBody, WireUsage, } from "./schemas.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { DEFAULT_TIMEOUT_MS, GATEWAY_API_KEY_ENV, GATEWAY_OIDC_ENV, GATEWAY_QUIRKS, SYSTEM_ONE_API_KEY_ENV, SYSTEM_ONE_DEFAULT_QUIRKS, SystemOneQuirks, TYPESAFE_API_KEY_ENV, } from "./config.js";
|
|
2
|
+
export { postEvaluate } from "./client.js";
|
|
3
|
+
export { evaluate } from "./evaluate.js";
|
|
4
|
+
export { createSystemOneAdapter, SYSTEM_ONE_PROVIDER } from "./adapter.js";
|
|
5
|
+
export { HttpError, NetworkError, SystemOneError, TimeoutError, } from "./errors.js";
|
|
6
|
+
export { drainTelemetryEvents, MAX_BUFFERED_TELEMETRY_EVENTS, recordTelemetryEvent, SystemOneTelemetryEvent, } from "./telemetry.js";
|
|
7
|
+
export { APPROXIMATE_SUM_TOLERANCE, BooleanQuestion, ChoiceQuestion, Confidence, Decision, Description, EndpointConfig, EvaluateConfig, EvaluateInput, EvaluateResult, EvaluateResponseBody, FallbackReason, FallbackResult, JsonRecord, NoulQuestion, ProbabilityMap, Question, QuestionList, ScoreQuestion, State, toDecision, toWireQuestions, Usage, WireAnswer, WireQuestion, WireRequest, WireResponseBody, WireUsage, } from "./schemas.js";
|