@corbits/system-one 0.3.2 → 0.4.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/README.md +62 -22
- package/dist/adapter.d.ts +1 -1
- package/dist/adapter.js +41 -7
- package/dist/assets.d.ts +36 -0
- package/dist/assets.js +232 -0
- package/dist/client.d.ts +5 -0
- package/dist/client.js +67 -2
- package/dist/config.d.ts +4 -0
- package/dist/config.js +4 -0
- package/dist/decisions.d.ts +99 -0
- package/dist/decisions.js +166 -0
- package/dist/evaluate.d.ts +15 -0
- package/dist/evaluate.js +28 -5
- package/dist/extraction.d.ts +104 -0
- package/dist/extraction.js +332 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +3 -1
- package/dist/schemas.d.ts +117 -7
- package/dist/schemas.js +96 -6
- package/package.json +11 -1
package/dist/schemas.js
CHANGED
|
@@ -88,11 +88,48 @@ export const BooleanQuestion = type({
|
|
|
88
88
|
},
|
|
89
89
|
"+": "reject",
|
|
90
90
|
}).narrow((q) => nonEmpty(q.instructions));
|
|
91
|
+
// Locates a region in an image. Edges come back as fractions of the image.
|
|
92
|
+
// Callers should set the model to `jev-preview`; the client does not require it.
|
|
93
|
+
export const BoxQuestion = type({
|
|
94
|
+
id: "string",
|
|
95
|
+
type: "'box'",
|
|
96
|
+
instructions: Description,
|
|
97
|
+
"+": "reject",
|
|
98
|
+
}).narrow((q) => nonEmpty(q.instructions));
|
|
99
|
+
// Keyed decisions questions: choice, noul, score, or box only. Extraction-style
|
|
100
|
+
// helpers are not part of this contract and fail the union.
|
|
101
|
+
export const DecisionQuestion = type({
|
|
102
|
+
type: "'choice'",
|
|
103
|
+
instructions: "unknown",
|
|
104
|
+
criteria: "unknown",
|
|
105
|
+
"+": "reject",
|
|
106
|
+
})
|
|
107
|
+
.or(type({
|
|
108
|
+
type: "'noul'",
|
|
109
|
+
"instructions?": "unknown",
|
|
110
|
+
"criteria?": "unknown",
|
|
111
|
+
"+": "reject",
|
|
112
|
+
}))
|
|
113
|
+
.or(type({
|
|
114
|
+
type: "'score'",
|
|
115
|
+
instructions: "unknown",
|
|
116
|
+
criteria: "unknown",
|
|
117
|
+
"+": "reject",
|
|
118
|
+
}))
|
|
119
|
+
.or(type({
|
|
120
|
+
type: "'box'",
|
|
121
|
+
instructions: "unknown",
|
|
122
|
+
"+": "reject",
|
|
123
|
+
}));
|
|
124
|
+
export const DecisionQuestionRecord = type({
|
|
125
|
+
"[string]": DecisionQuestion,
|
|
126
|
+
}).narrow((qs) => Object.keys(qs).length >= 1);
|
|
91
127
|
// The question union a caller may ask in one evaluation. `.or` chains keep
|
|
92
128
|
// each branch's literal `type`, so the union still discriminates on it.
|
|
93
129
|
export const Question = ChoiceQuestion.or(ScoreQuestion)
|
|
94
130
|
.or(NoulQuestion)
|
|
95
|
-
.or(BooleanQuestion)
|
|
131
|
+
.or(BooleanQuestion)
|
|
132
|
+
.or(BoxQuestion);
|
|
96
133
|
// A non-empty question list with unique ids: a duplicate would make the
|
|
97
134
|
// backend's per-id echo permanently ambiguous, so it is rejected at the
|
|
98
135
|
// input edge (typed `SystemOneError` / `ProtocolMismatchError`) rather than
|
|
@@ -107,10 +144,13 @@ export const QuestionList = Question.array()
|
|
|
107
144
|
// `gateway` the proxy endpoint, `custom` a caller-supplied URL. `url` only
|
|
108
145
|
// exists on `custom` — a `url` on another kind would be silently ignored,
|
|
109
146
|
// so the schema rejects it instead of accepting misleading config.
|
|
147
|
+
// `auth: "none"` exists only on `custom`: it is the explicit opt-out from
|
|
148
|
+
// the fail-closed key requirement. Official and gateway cannot carry it.
|
|
110
149
|
export const EndpointConfig = type({
|
|
111
150
|
kind: "'custom'",
|
|
112
151
|
url: "string",
|
|
113
152
|
"model?": "string",
|
|
153
|
+
"auth?": "'none'",
|
|
114
154
|
"+": "reject",
|
|
115
155
|
}).or(type({
|
|
116
156
|
kind: "'official' | 'gateway'",
|
|
@@ -146,16 +186,22 @@ export const EvaluateInput = type({
|
|
|
146
186
|
// `toWireRequest`, never hand-assembled by callers.
|
|
147
187
|
/** One question in wire form: no id (the map key carries it). */
|
|
148
188
|
export const WireQuestion = type({
|
|
149
|
-
type: "'noul' | 'choice' | 'score'",
|
|
189
|
+
type: "'noul' | 'choice' | 'score' | 'box'",
|
|
150
190
|
instructions: Description,
|
|
151
191
|
"criteria?": "unknown",
|
|
152
192
|
"+": "reject",
|
|
153
193
|
});
|
|
154
|
-
|
|
194
|
+
const WireAsset = type({
|
|
195
|
+
type: "'image'",
|
|
196
|
+
part: "string",
|
|
197
|
+
"+": "reject",
|
|
198
|
+
});
|
|
199
|
+
/** The exact POST body: model + state + id-keyed questions, plus image parts. */
|
|
155
200
|
export const WireRequest = type({
|
|
156
201
|
model: "string",
|
|
157
202
|
state: State,
|
|
158
203
|
questions: { "[string]": WireQuestion },
|
|
204
|
+
"assets?": { "[string]": WireAsset },
|
|
159
205
|
"+": "reject",
|
|
160
206
|
}).narrow((body) => Object.keys(body.questions).length >= 1);
|
|
161
207
|
/**
|
|
@@ -169,8 +215,9 @@ export function toWireQuestions(questions) {
|
|
|
169
215
|
type: question.type === "boolean" ? "noul" : question.type,
|
|
170
216
|
instructions: question.instructions,
|
|
171
217
|
};
|
|
172
|
-
if (question.criteria !== undefined)
|
|
218
|
+
if ("criteria" in question && question.criteria !== undefined) {
|
|
173
219
|
mapped.criteria = question.criteria;
|
|
220
|
+
}
|
|
174
221
|
wire[question.id] = mapped;
|
|
175
222
|
}
|
|
176
223
|
return wire;
|
|
@@ -193,14 +240,36 @@ export const APPROXIMATE_SUM_TOLERANCE = 0.02;
|
|
|
193
240
|
// `type` must carry. No `"+": "reject"`: the backend may attach per-answer
|
|
194
241
|
// metadata that `toDecision` strips.
|
|
195
242
|
export const WireAnswer = type({
|
|
196
|
-
type: "'noul' | 'choice' | 'score'",
|
|
243
|
+
type: "'noul' | 'choice' | 'score' | 'box'",
|
|
197
244
|
"choice?": "string",
|
|
198
245
|
"score?": "number",
|
|
199
246
|
"noul?": Confidence,
|
|
200
247
|
"probabilities?": ProbabilityMap,
|
|
201
|
-
"confidence?": Confidence,
|
|
248
|
+
"confidence?": Confidence.or("null"),
|
|
202
249
|
"legend?": { "[string]": "string" },
|
|
250
|
+
"box?": {
|
|
251
|
+
top: "number",
|
|
252
|
+
bottom: "number",
|
|
253
|
+
left: "number",
|
|
254
|
+
right: "number",
|
|
255
|
+
},
|
|
203
256
|
});
|
|
257
|
+
/** Box edges are fractions of the image. Shared by `evaluate` and the adapter. */
|
|
258
|
+
export function boxEdgesOutOfRange(id, box) {
|
|
259
|
+
for (const edge of ["top", "bottom", "left", "right"]) {
|
|
260
|
+
const value = box[edge];
|
|
261
|
+
if (!Number.isFinite(value) || value < 0 || value > 1) {
|
|
262
|
+
return `answer "${id}" box.${edge} ${String(value)} outside [0, 1]`;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
if (box.top >= box.bottom) {
|
|
266
|
+
return `answer "${id}" box.top ${String(box.top)} is not below box.bottom ${String(box.bottom)}`;
|
|
267
|
+
}
|
|
268
|
+
if (box.left >= box.right) {
|
|
269
|
+
return `answer "${id}" box.left ${String(box.left)} is not left of box.right ${String(box.right)}`;
|
|
270
|
+
}
|
|
271
|
+
return undefined;
|
|
272
|
+
}
|
|
204
273
|
// Token usage reported on the response envelope.
|
|
205
274
|
export const WireUsage = type({
|
|
206
275
|
input_tokens: "number",
|
|
@@ -241,6 +310,19 @@ export const Decision = type({
|
|
|
241
310
|
probabilities: ProbabilityMap,
|
|
242
311
|
confidence: Confidence,
|
|
243
312
|
"+": "reject",
|
|
313
|
+
}))
|
|
314
|
+
.or(type({
|
|
315
|
+
id: "string",
|
|
316
|
+
type: "'box'",
|
|
317
|
+
box: {
|
|
318
|
+
top: "number",
|
|
319
|
+
bottom: "number",
|
|
320
|
+
left: "number",
|
|
321
|
+
right: "number",
|
|
322
|
+
"+": "reject",
|
|
323
|
+
},
|
|
324
|
+
confidence: Confidence.or("null"),
|
|
325
|
+
"+": "reject",
|
|
244
326
|
}));
|
|
245
327
|
/**
|
|
246
328
|
* Builds a caller-facing decision from a wire answer: the kind's contract
|
|
@@ -262,6 +344,14 @@ export function toDecision(id, answer) {
|
|
|
262
344
|
confidence: answer.confidence,
|
|
263
345
|
};
|
|
264
346
|
}
|
|
347
|
+
else if (answer.type === "box") {
|
|
348
|
+
candidate = {
|
|
349
|
+
id,
|
|
350
|
+
type: "box",
|
|
351
|
+
box: answer.box,
|
|
352
|
+
confidence: answer.confidence ?? null,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
265
355
|
else {
|
|
266
356
|
candidate = {
|
|
267
357
|
id,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@corbits/system-one",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Typed-decision evaluation client for System One (Jev-class) models: arktype question/decision schemas, endpoint configuration with gateway override, and timeout/fallback semantics.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"corbits",
|
|
@@ -32,6 +32,16 @@
|
|
|
32
32
|
"corbits-system-one-src": "./src/index.ts",
|
|
33
33
|
"types": "./dist/index.d.ts",
|
|
34
34
|
"default": "./dist/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./decisions": {
|
|
37
|
+
"corbits-system-one-src": "./src/decisions.ts",
|
|
38
|
+
"types": "./dist/decisions.d.ts",
|
|
39
|
+
"default": "./dist/decisions.js"
|
|
40
|
+
},
|
|
41
|
+
"./extraction": {
|
|
42
|
+
"corbits-system-one-src": "./src/extraction.ts",
|
|
43
|
+
"types": "./dist/extraction.d.ts",
|
|
44
|
+
"default": "./dist/extraction.js"
|
|
35
45
|
}
|
|
36
46
|
},
|
|
37
47
|
"publishConfig": {
|