@itsoltech/basal-client 0.2.0 → 0.3.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 +17 -3
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/index.d.cts +15 -3
- package/dist/cjs/questions.cjs +7 -2
- package/dist/cjs/questions.d.cts +2 -0
- package/dist/cjs/tasks.cjs +175 -0
- package/dist/cjs/tasks.d.cts +108 -0
- package/dist/esm/index.d.ts +15 -3
- package/dist/esm/index.js +1 -0
- package/dist/esm/questions.d.ts +2 -0
- package/dist/esm/questions.js +7 -2
- package/dist/esm/tasks.d.ts +108 -0
- package/dist/esm/tasks.js +164 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -103,14 +103,28 @@ Usage exposes `longest_prompt_tokens`, `second_order_branches` and media counts,
|
|
|
103
103
|
soft tokens and detail. Discovery exposes `prompt_format`, `orders`, enabled
|
|
104
104
|
media and calibration temperatures. Model names remain strings: use exact names
|
|
105
105
|
from model discovery, not a hardcoded model enumeration. Keep old models and
|
|
106
|
-
raw JSON access available.
|
|
107
|
-
|
|
106
|
+
raw JSON access available. The server validates each model’s capabilities.
|
|
107
|
+
Basal 2.1 task helpers are described below.
|
|
108
108
|
|
|
109
109
|
```typescript
|
|
110
110
|
import { BasalClient, image, tool, multi } from "@itsoltech/basal-client";
|
|
111
111
|
const response = await new BasalClient().decide("Inspect the supplied material.", {
|
|
112
|
-
route: tool("Choose a tool.", [{name:"inspect", description:"Inspect material", inputSchema:{type:"object"}}], {extra:["none"], rank:2}),
|
|
112
|
+
route: tool("Choose a tool.", [{name:"inspect", description:"Inspect material", inputSchema:{type:"object"}}], {extra:["none"], rank:2, description_chars:120}),
|
|
113
113
|
labels: multi("Select visible objects.", {animal:"An animal", vehicle:"A vehicle"}, {objective:"f1"}),
|
|
114
114
|
}, {model:"basal-omni-1.0-mini", lang:"en", media:[image(new Uint8Array(await file.arrayBuffer()))]});
|
|
115
115
|
console.log(response.answers.route, response.answers.labels.expected_score);
|
|
116
116
|
```
|
|
117
|
+
|
|
118
|
+
Tool descriptions are normalized by the server. Omit `description_chars`
|
|
119
|
+
(`DescriptionChars` in .NET) to keep the default cap of 300 Unicode code points;
|
|
120
|
+
use `0` to disable truncation. Descriptions longer than a positive cap are
|
|
121
|
+
shortened at a word boundary where possible, with an ellipsis appended. The SDK forwards this option
|
|
122
|
+
without changing the supplied tool definitions.
|
|
123
|
+
|
|
124
|
+
## Experimental Basal 2.1 tasks
|
|
125
|
+
|
|
126
|
+
Typed classify, verify, compress and extract factories preserve nullable task automation,
|
|
127
|
+
Unicode code point offsets and nested JSON extraction values. Task answers do not share
|
|
128
|
+
the primitive probabilities field. See [task semantics](../../docs/TASKS.md) and
|
|
129
|
+
[SDK examples](../../docs/SDK.md#zadania-basal-21). These source changes require a server
|
|
130
|
+
with the experimental task layer; installing an SDK does not update the inference server.
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -18,6 +18,7 @@ exports.BasalClient = exports.BasalResponseTooLargeError = exports.BasalProtocol
|
|
|
18
18
|
const questions_cjs_1 = require("./questions.cjs");
|
|
19
19
|
__exportStar(require("./questions.cjs"), exports);
|
|
20
20
|
__exportStar(require("./media.cjs"), exports);
|
|
21
|
+
__exportStar(require("./tasks.cjs"), exports);
|
|
21
22
|
class BasalError extends Error {
|
|
22
23
|
}
|
|
23
24
|
exports.BasalError = BasalError;
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type QuestionSet, type TypedDecisionResponse, type DecisionOptions } from "./questions.cjs";
|
|
2
2
|
export * from "./questions.cjs";
|
|
3
3
|
export * from "./media.cjs";
|
|
4
|
+
export * from "./tasks.cjs";
|
|
5
|
+
import type { TaskAnswer } from "./tasks.cjs";
|
|
4
6
|
/** Native Basal wire types. Criterion order is significant; do not sort keys. */
|
|
5
7
|
export type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
6
8
|
[key: string]: JsonValue;
|
|
@@ -23,7 +25,7 @@ export interface ToolRanking {
|
|
|
23
25
|
}
|
|
24
26
|
export type ToolDefinition = Record<string, JsonValue>;
|
|
25
27
|
export interface Question {
|
|
26
|
-
type?: "choice" | "noul" | "score" | "multi" | "act" | "tool";
|
|
28
|
+
type?: "choice" | "noul" | "score" | "multi" | "act" | "tool" | "classify" | "verify" | "compress" | "extract";
|
|
27
29
|
instructions?: JsonValue;
|
|
28
30
|
criteria?: Record<string, JsonValue> | JsonValue[];
|
|
29
31
|
levels?: Record<string, JsonValue> | JsonValue[];
|
|
@@ -35,7 +37,7 @@ export interface Question {
|
|
|
35
37
|
base?: "noul" | "choice" | "score";
|
|
36
38
|
costs?: Record<string, number> | Record<string, Record<string, number>>;
|
|
37
39
|
defer_action?: string;
|
|
38
|
-
max_error?: number;
|
|
40
|
+
max_error?: number | readonly number[];
|
|
39
41
|
objective?: MultiObjective;
|
|
40
42
|
exclusive?: readonly string[];
|
|
41
43
|
fallback?: string;
|
|
@@ -43,7 +45,17 @@ export interface Question {
|
|
|
43
45
|
tools?: readonly ToolDefinition[];
|
|
44
46
|
extra?: readonly ("answer_directly" | "ask_user" | "none")[];
|
|
45
47
|
rank?: number;
|
|
48
|
+
description_chars?: number;
|
|
46
49
|
multi?: boolean;
|
|
50
|
+
labels?: Record<string, JsonValue> | JsonValue[];
|
|
51
|
+
multi_label?: boolean;
|
|
52
|
+
none?: boolean;
|
|
53
|
+
claims?: Record<string, JsonValue> | JsonValue[];
|
|
54
|
+
binary?: boolean;
|
|
55
|
+
unit?: 'sentence' | 'line' | 'paragraph';
|
|
56
|
+
keep_ratio?: number;
|
|
57
|
+
min_keep?: number;
|
|
58
|
+
schema?: Record<string, JsonValue>;
|
|
47
59
|
}
|
|
48
60
|
export interface DecisionRequest {
|
|
49
61
|
state: JsonValue;
|
|
@@ -122,7 +134,7 @@ export interface ActAnswer<K extends string = string, A extends string = string>
|
|
|
122
134
|
max_error?: string;
|
|
123
135
|
deferred?: boolean;
|
|
124
136
|
}
|
|
125
|
-
export type Answer = ChoiceAnswer | NoulAnswer | ScoreAnswer | MultiAnswer | ActAnswer | ToolAnswer;
|
|
137
|
+
export type Answer = ChoiceAnswer | NoulAnswer | ScoreAnswer | MultiAnswer | ActAnswer | ToolAnswer | TaskAnswer;
|
|
126
138
|
export interface Usage {
|
|
127
139
|
input_tokens: number;
|
|
128
140
|
output_tokens: number;
|
package/dist/cjs/questions.cjs
CHANGED
|
@@ -40,13 +40,13 @@ function evidence(options) {
|
|
|
40
40
|
class QuestionSpec {
|
|
41
41
|
wire;
|
|
42
42
|
constructor(kind, instructions, fields) {
|
|
43
|
-
this.wire = structuredClone({ ...fields, type: kind, instructions: text(instructions, 'instructions') });
|
|
43
|
+
this.wire = structuredClone({ ...fields, type: kind, ...(['classify', 'verify', 'compress', 'extract'].includes(kind) ? (instructions ? { instructions } : {}) : { instructions: text(instructions, 'instructions') }) });
|
|
44
44
|
}
|
|
45
45
|
toJSON() { return structuredClone(this.wire); }
|
|
46
46
|
/** Validate and retrieve an answer with this question's result type. */
|
|
47
47
|
read(response, id) {
|
|
48
48
|
const answer = response.answers?.[id];
|
|
49
|
-
if (!answer || answer.type !== this.wire.type || !answer.probabilities || typeof answer.probabilities !== 'object' || Array.isArray(answer.probabilities)) {
|
|
49
|
+
if (!answer || !('probabilities' in answer) || answer.type !== this.wire.type || !answer.probabilities || typeof answer.probabilities !== 'object' || Array.isArray(answer.probabilities)) {
|
|
50
50
|
throw new TypeError('Basal returned a missing or mismatched answer');
|
|
51
51
|
}
|
|
52
52
|
const fields = {
|
|
@@ -216,6 +216,11 @@ class ToolQuestion extends QuestionSpec {
|
|
|
216
216
|
if (options.multi !== undefined && typeof options.multi !== 'boolean')
|
|
217
217
|
throw new TypeError('invalid multi');
|
|
218
218
|
const fields = { tools, ...(options.extra === undefined ? {} : { extra: options.extra }) };
|
|
219
|
+
if (options.description_chars !== undefined) {
|
|
220
|
+
if (!Number.isSafeInteger(options.description_chars) || options.description_chars < 0)
|
|
221
|
+
throw new TypeError('description_chars must be a non-negative safe integer');
|
|
222
|
+
fields.description_chars = options.description_chars;
|
|
223
|
+
}
|
|
219
224
|
if (options.rank !== undefined) {
|
|
220
225
|
if (!Number.isSafeInteger(options.rank) || options.rank < 1)
|
|
221
226
|
throw new TypeError('rank must be a positive integer');
|
package/dist/cjs/questions.d.cts
CHANGED
|
@@ -33,6 +33,8 @@ export interface ToolOptions extends MultiOptions {
|
|
|
33
33
|
rank?: number;
|
|
34
34
|
multi?: boolean;
|
|
35
35
|
max_error?: number;
|
|
36
|
+
/** Tool-description truncation cap; omitted keeps the server default (300), zero disables truncation. */
|
|
37
|
+
description_chars?: number;
|
|
36
38
|
}
|
|
37
39
|
export interface ActOptions<K extends string = string, A extends string = string> extends EvidenceOptions {
|
|
38
40
|
criteria?: Record<K, string>;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExtractQuestion = exports.CompressQuestion = exports.VerifyQuestion = exports.ClassifyQuestion = void 0;
|
|
4
|
+
exports.classify = classify;
|
|
5
|
+
exports.verify = verify;
|
|
6
|
+
exports.compress = compress;
|
|
7
|
+
exports.extract = extract;
|
|
8
|
+
const questions_cjs_1 = require("./questions.cjs");
|
|
9
|
+
function object(v) {
|
|
10
|
+
if (!v || typeof v !== 'object' || Array.isArray(v))
|
|
11
|
+
throw new TypeError('expected task object');
|
|
12
|
+
return v;
|
|
13
|
+
}
|
|
14
|
+
function probability(v) { if (typeof v !== 'number' || !Number.isFinite(v) || v < 0 || v > 1)
|
|
15
|
+
throw new TypeError('invalid probability'); }
|
|
16
|
+
function probabilities(v) { for (const n of Object.values(object(v)))
|
|
17
|
+
probability(n); }
|
|
18
|
+
function automation(v) { if (Object.values(object(v)).some(n => n !== null && typeof n !== 'boolean'))
|
|
19
|
+
throw new TypeError('invalid automation'); }
|
|
20
|
+
function strings(v) { if (!Array.isArray(v) || v.some(k => typeof k !== 'string'))
|
|
21
|
+
throw new TypeError('expected string list'); }
|
|
22
|
+
function offset(v) { if (!Number.isSafeInteger(v) || v < 0)
|
|
23
|
+
throw new TypeError('invalid Unicode code point offset/count'); }
|
|
24
|
+
function span(v) { offset(v.start); offset(v.end); if (v.end < v.start)
|
|
25
|
+
throw new TypeError('reversed source span'); }
|
|
26
|
+
function risks(v) {
|
|
27
|
+
if (v === undefined)
|
|
28
|
+
return;
|
|
29
|
+
const a = Array.isArray(v) ? v : [v];
|
|
30
|
+
if (a.length > 64 || a.some(n => typeof n !== 'number' || !Number.isFinite(n) || n <= 0 || n >= 1))
|
|
31
|
+
throw new TypeError('invalid max_error');
|
|
32
|
+
}
|
|
33
|
+
function instructions(v) { if (typeof v !== 'string')
|
|
34
|
+
throw new TypeError('instructions must be a string'); return v; }
|
|
35
|
+
class TaskQuestion extends questions_cjs_1.QuestionSpec {
|
|
36
|
+
constructor(kind, text, fields) { super(kind, instructions(text), fields); }
|
|
37
|
+
read(response, id) {
|
|
38
|
+
const d = object(response.answers?.[id]);
|
|
39
|
+
if (d.type !== this.toJSON().type || d.experimental !== true)
|
|
40
|
+
throw new TypeError('Basal returned a missing or mismatched task');
|
|
41
|
+
if (d.type === 'classify') {
|
|
42
|
+
probabilities(d.scores);
|
|
43
|
+
const scores = object(d.scores);
|
|
44
|
+
if (this.toJSON().multi_label) {
|
|
45
|
+
strings(d.labels);
|
|
46
|
+
if (d.labels.some(k => !Object.hasOwn(scores, k)))
|
|
47
|
+
throw new TypeError('unknown label');
|
|
48
|
+
probability(d.set_confidence);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
if (typeof d.label !== 'string' || !Object.hasOwn(scores, d.label) || d.top_label !== d.label)
|
|
52
|
+
throw new TypeError('invalid label');
|
|
53
|
+
probability(d.confidence);
|
|
54
|
+
automation(d.automated);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else if (d.type === 'verify') {
|
|
58
|
+
const claims = object(d.claims);
|
|
59
|
+
for (const raw of Object.values(claims)) {
|
|
60
|
+
const c = object(raw);
|
|
61
|
+
const p = object(c.probabilities);
|
|
62
|
+
probabilities(p);
|
|
63
|
+
if (typeof c.verdict !== 'string' || !['supported', 'contradicted', 'not_stated', 'not_supported'].includes(c.verdict) || !Object.hasOwn(p, c.verdict))
|
|
64
|
+
throw new TypeError('invalid verdict');
|
|
65
|
+
probability(c.confidence);
|
|
66
|
+
automation(c.automated);
|
|
67
|
+
}
|
|
68
|
+
strings(d.not_supported);
|
|
69
|
+
if (typeof d.all_supported !== 'boolean' || d.not_supported.some(k => !Object.hasOwn(claims, k)))
|
|
70
|
+
throw new TypeError('invalid verification summary');
|
|
71
|
+
}
|
|
72
|
+
else if (d.type === 'compress') {
|
|
73
|
+
if (typeof d.compressed !== 'string' || !['sentence', 'line', 'paragraph'].includes(d.unit) || !Array.isArray(d.units) || !Array.isArray(d.kept))
|
|
74
|
+
throw new TypeError('invalid compression');
|
|
75
|
+
for (const u of d.units) {
|
|
76
|
+
const v = object(u);
|
|
77
|
+
span(v);
|
|
78
|
+
probability(v.probability);
|
|
79
|
+
}
|
|
80
|
+
for (const k of d.kept) {
|
|
81
|
+
offset(k);
|
|
82
|
+
if (k >= d.units.length)
|
|
83
|
+
throw new TypeError('invalid kept unit');
|
|
84
|
+
}
|
|
85
|
+
offset(d.original_chars);
|
|
86
|
+
offset(d.compressed_chars);
|
|
87
|
+
if (typeof d.ratio !== 'number' || !Number.isFinite(d.ratio) || d.ratio < 0)
|
|
88
|
+
throw new TypeError('invalid ratio');
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
object(d.data);
|
|
92
|
+
for (const raw of Object.values(object(d.fields))) {
|
|
93
|
+
const f = object(raw);
|
|
94
|
+
if (!Object.hasOwn(f, 'value') || !['choice', 'span'].includes(f.source) || !['validated', 'per decision'].includes(f.calibration))
|
|
95
|
+
throw new TypeError('invalid extraction field');
|
|
96
|
+
probability(f.confidence);
|
|
97
|
+
if (f.probabilities !== undefined)
|
|
98
|
+
probabilities(f.probabilities);
|
|
99
|
+
for (const k of ['present_probability', 'line_probability', 'span_probability'])
|
|
100
|
+
if (f[k] !== undefined)
|
|
101
|
+
probability(f[k]);
|
|
102
|
+
if (f.text !== undefined) {
|
|
103
|
+
if (typeof f.text !== 'string')
|
|
104
|
+
throw new TypeError('invalid source text');
|
|
105
|
+
span(f);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return structuredClone(d);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
class ClassifyQuestion extends TaskQuestion {
|
|
113
|
+
constructor(text, labels, options = {}) {
|
|
114
|
+
if (!labels || typeof labels !== 'object' || Object.keys(labels).length < 1 || Object.keys(labels).length > 256)
|
|
115
|
+
throw new TypeError('classify requires 1..256 labels');
|
|
116
|
+
risks(options.max_error);
|
|
117
|
+
for (const k of ['multi_label', 'none'])
|
|
118
|
+
if (options[k] !== undefined && typeof options[k] !== 'boolean')
|
|
119
|
+
throw new TypeError(`invalid ${k}`);
|
|
120
|
+
if (options.option_keys !== undefined && !['show', 'hide'].includes(options.option_keys))
|
|
121
|
+
throw new TypeError('invalid option_keys');
|
|
122
|
+
if (options.threshold !== undefined) {
|
|
123
|
+
probability(options.threshold);
|
|
124
|
+
if (options.objective !== undefined && options.objective !== 'threshold')
|
|
125
|
+
throw new TypeError('threshold requires threshold objective');
|
|
126
|
+
}
|
|
127
|
+
for (const k of ['min', 'max'])
|
|
128
|
+
if (options[k] !== undefined)
|
|
129
|
+
offset(options[k]);
|
|
130
|
+
if (options.min !== undefined && options.max !== undefined && options.min > options.max)
|
|
131
|
+
throw new TypeError('min exceeds max');
|
|
132
|
+
if (options.objective !== undefined && !['threshold', 'exact', 'iou', 'f1'].includes(options.objective))
|
|
133
|
+
throw new TypeError('invalid objective');
|
|
134
|
+
if (!options.multi_label && ['threshold', 'min', 'max', 'objective'].some(k => Object.hasOwn(options, k)))
|
|
135
|
+
throw new TypeError('selection options require multi_label');
|
|
136
|
+
super('classify', text, { labels: structuredClone(labels), ...options });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
exports.ClassifyQuestion = ClassifyQuestion;
|
|
140
|
+
class VerifyQuestion extends TaskQuestion {
|
|
141
|
+
constructor(text, claims, options = {}) {
|
|
142
|
+
if (!claims || typeof claims !== 'object' || !Object.keys(claims).length)
|
|
143
|
+
throw new TypeError('verify requires claims');
|
|
144
|
+
risks(options.max_error);
|
|
145
|
+
if (options.binary !== undefined && typeof options.binary !== 'boolean')
|
|
146
|
+
throw new TypeError('invalid binary');
|
|
147
|
+
super('verify', text, { claims: structuredClone(claims), ...options });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
exports.VerifyQuestion = VerifyQuestion;
|
|
151
|
+
class CompressQuestion extends TaskQuestion {
|
|
152
|
+
constructor(text = '', options = {}) {
|
|
153
|
+
if (options.unit !== undefined && !['sentence', 'line', 'paragraph'].includes(options.unit))
|
|
154
|
+
throw new TypeError('invalid unit');
|
|
155
|
+
if (options.keep_ratio !== undefined) {
|
|
156
|
+
probability(options.keep_ratio);
|
|
157
|
+
if (options.keep_ratio === 0)
|
|
158
|
+
throw new TypeError('keep_ratio must be positive');
|
|
159
|
+
}
|
|
160
|
+
if (options.threshold !== undefined)
|
|
161
|
+
probability(options.threshold);
|
|
162
|
+
if (options.min_keep !== undefined)
|
|
163
|
+
offset(options.min_keep);
|
|
164
|
+
super('compress', text, options);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
exports.CompressQuestion = CompressQuestion;
|
|
168
|
+
class ExtractQuestion extends TaskQuestion {
|
|
169
|
+
constructor(text, schema) { object(schema); super('extract', text, { schema }); }
|
|
170
|
+
}
|
|
171
|
+
exports.ExtractQuestion = ExtractQuestion;
|
|
172
|
+
function classify(text, labels, options) { return new ClassifyQuestion(text, labels, options); }
|
|
173
|
+
function verify(text, claims, options) { return new VerifyQuestion(text, claims, options); }
|
|
174
|
+
function compress(text = '', options) { return new CompressQuestion(text, options); }
|
|
175
|
+
function extract(text, schema) { return new ExtractQuestion(text, schema); }
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { QuestionSpec } from './questions.cjs';
|
|
2
|
+
import type { DecisionResponse, JsonValue, Question, MultiObjective } from './index.cjs';
|
|
3
|
+
/** Task automation is unknown (null) without a threshold certified for that task/error target. */
|
|
4
|
+
export type Automation = Record<string, boolean | null>;
|
|
5
|
+
export interface ClassifyAnswer<K extends string = string> {
|
|
6
|
+
type: 'classify';
|
|
7
|
+
experimental: true;
|
|
8
|
+
scores: Record<K, number>;
|
|
9
|
+
label?: K;
|
|
10
|
+
top_label?: K;
|
|
11
|
+
confidence?: number;
|
|
12
|
+
automated?: Automation;
|
|
13
|
+
labels?: K[];
|
|
14
|
+
set_confidence?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface ClaimResult {
|
|
17
|
+
verdict: 'supported' | 'contradicted' | 'not_stated' | 'not_supported';
|
|
18
|
+
probabilities: Record<string, number>;
|
|
19
|
+
confidence: number;
|
|
20
|
+
automated: Automation;
|
|
21
|
+
}
|
|
22
|
+
export interface VerifyAnswer {
|
|
23
|
+
type: 'verify';
|
|
24
|
+
experimental: true;
|
|
25
|
+
claims: Record<string, ClaimResult>;
|
|
26
|
+
all_supported: boolean;
|
|
27
|
+
not_supported: string[];
|
|
28
|
+
}
|
|
29
|
+
/** Inclusive start/exclusive end count Unicode code points, not JavaScript UTF-16 units. */
|
|
30
|
+
export interface CompressionUnit {
|
|
31
|
+
start: number;
|
|
32
|
+
end: number;
|
|
33
|
+
probability: number;
|
|
34
|
+
}
|
|
35
|
+
export interface CompressAnswer {
|
|
36
|
+
type: 'compress';
|
|
37
|
+
experimental: true;
|
|
38
|
+
compressed: string;
|
|
39
|
+
kept: number[];
|
|
40
|
+
units: CompressionUnit[];
|
|
41
|
+
unit: 'sentence' | 'line' | 'paragraph';
|
|
42
|
+
original_chars: number;
|
|
43
|
+
compressed_chars: number;
|
|
44
|
+
ratio: number;
|
|
45
|
+
}
|
|
46
|
+
export interface ExtractField {
|
|
47
|
+
value: JsonValue;
|
|
48
|
+
confidence: number;
|
|
49
|
+
source: 'choice' | 'span';
|
|
50
|
+
calibration: 'validated' | 'per decision';
|
|
51
|
+
probabilities?: Record<string, number>;
|
|
52
|
+
present_probability?: number;
|
|
53
|
+
text?: string;
|
|
54
|
+
start?: number;
|
|
55
|
+
end?: number;
|
|
56
|
+
line_probability?: number;
|
|
57
|
+
span_probability?: number;
|
|
58
|
+
error?: string;
|
|
59
|
+
}
|
|
60
|
+
export interface ExtractAnswer {
|
|
61
|
+
type: 'extract';
|
|
62
|
+
experimental: true;
|
|
63
|
+
data: Record<string, JsonValue>;
|
|
64
|
+
fields: Record<string, ExtractField>;
|
|
65
|
+
}
|
|
66
|
+
export type TaskAnswer = ClassifyAnswer | VerifyAnswer | CompressAnswer | ExtractAnswer;
|
|
67
|
+
export interface ClassifyOptions {
|
|
68
|
+
multi_label?: boolean;
|
|
69
|
+
none?: boolean;
|
|
70
|
+
max_error?: number | readonly number[];
|
|
71
|
+
option_keys?: 'show' | 'hide';
|
|
72
|
+
threshold?: number;
|
|
73
|
+
min?: number;
|
|
74
|
+
max?: number;
|
|
75
|
+
objective?: MultiObjective;
|
|
76
|
+
}
|
|
77
|
+
export interface VerifyOptions {
|
|
78
|
+
binary?: boolean;
|
|
79
|
+
max_error?: number | readonly number[];
|
|
80
|
+
}
|
|
81
|
+
export interface CompressOptions {
|
|
82
|
+
unit?: 'sentence' | 'line' | 'paragraph';
|
|
83
|
+
keep_ratio?: number;
|
|
84
|
+
threshold?: number;
|
|
85
|
+
min_keep?: number;
|
|
86
|
+
}
|
|
87
|
+
declare abstract class TaskQuestion<A extends TaskAnswer> extends QuestionSpec<A> {
|
|
88
|
+
protected constructor(kind: A['type'], text: string, fields: Question);
|
|
89
|
+
read(response: DecisionResponse, id: string): A;
|
|
90
|
+
}
|
|
91
|
+
export declare class ClassifyQuestion<K extends string = string> extends TaskQuestion<ClassifyAnswer<K>> {
|
|
92
|
+
constructor(text: string, labels: Record<K, JsonValue> | readonly JsonValue[], options?: ClassifyOptions);
|
|
93
|
+
}
|
|
94
|
+
export declare class VerifyQuestion extends TaskQuestion<VerifyAnswer> {
|
|
95
|
+
constructor(text: string, claims: Record<string, JsonValue> | readonly JsonValue[], options?: VerifyOptions);
|
|
96
|
+
}
|
|
97
|
+
export declare class CompressQuestion extends TaskQuestion<CompressAnswer> {
|
|
98
|
+
constructor(text?: string, options?: CompressOptions);
|
|
99
|
+
}
|
|
100
|
+
export declare class ExtractQuestion extends TaskQuestion<ExtractAnswer> {
|
|
101
|
+
constructor(text: string, schema: Record<string, JsonValue>);
|
|
102
|
+
}
|
|
103
|
+
export declare function classify<const K extends string>(text: string, labels: Record<K, JsonValue>, options?: ClassifyOptions): ClassifyQuestion<K>;
|
|
104
|
+
export declare function classify(text: string, labels: readonly JsonValue[], options?: ClassifyOptions): ClassifyQuestion;
|
|
105
|
+
export declare function verify(text: string, claims: Record<string, JsonValue> | readonly JsonValue[], options?: VerifyOptions): VerifyQuestion;
|
|
106
|
+
export declare function compress(text?: string, options?: CompressOptions): CompressQuestion;
|
|
107
|
+
export declare function extract(text: string, schema: Record<string, JsonValue>): ExtractQuestion;
|
|
108
|
+
export {};
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type QuestionSet, type TypedDecisionResponse, type DecisionOptions } from "./questions.js";
|
|
2
2
|
export * from "./questions.js";
|
|
3
3
|
export * from "./media.js";
|
|
4
|
+
export * from "./tasks.js";
|
|
5
|
+
import type { TaskAnswer } from "./tasks.js";
|
|
4
6
|
/** Native Basal wire types. Criterion order is significant; do not sort keys. */
|
|
5
7
|
export type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
6
8
|
[key: string]: JsonValue;
|
|
@@ -23,7 +25,7 @@ export interface ToolRanking {
|
|
|
23
25
|
}
|
|
24
26
|
export type ToolDefinition = Record<string, JsonValue>;
|
|
25
27
|
export interface Question {
|
|
26
|
-
type?: "choice" | "noul" | "score" | "multi" | "act" | "tool";
|
|
28
|
+
type?: "choice" | "noul" | "score" | "multi" | "act" | "tool" | "classify" | "verify" | "compress" | "extract";
|
|
27
29
|
instructions?: JsonValue;
|
|
28
30
|
criteria?: Record<string, JsonValue> | JsonValue[];
|
|
29
31
|
levels?: Record<string, JsonValue> | JsonValue[];
|
|
@@ -35,7 +37,7 @@ export interface Question {
|
|
|
35
37
|
base?: "noul" | "choice" | "score";
|
|
36
38
|
costs?: Record<string, number> | Record<string, Record<string, number>>;
|
|
37
39
|
defer_action?: string;
|
|
38
|
-
max_error?: number;
|
|
40
|
+
max_error?: number | readonly number[];
|
|
39
41
|
objective?: MultiObjective;
|
|
40
42
|
exclusive?: readonly string[];
|
|
41
43
|
fallback?: string;
|
|
@@ -43,7 +45,17 @@ export interface Question {
|
|
|
43
45
|
tools?: readonly ToolDefinition[];
|
|
44
46
|
extra?: readonly ("answer_directly" | "ask_user" | "none")[];
|
|
45
47
|
rank?: number;
|
|
48
|
+
description_chars?: number;
|
|
46
49
|
multi?: boolean;
|
|
50
|
+
labels?: Record<string, JsonValue> | JsonValue[];
|
|
51
|
+
multi_label?: boolean;
|
|
52
|
+
none?: boolean;
|
|
53
|
+
claims?: Record<string, JsonValue> | JsonValue[];
|
|
54
|
+
binary?: boolean;
|
|
55
|
+
unit?: 'sentence' | 'line' | 'paragraph';
|
|
56
|
+
keep_ratio?: number;
|
|
57
|
+
min_keep?: number;
|
|
58
|
+
schema?: Record<string, JsonValue>;
|
|
47
59
|
}
|
|
48
60
|
export interface DecisionRequest {
|
|
49
61
|
state: JsonValue;
|
|
@@ -122,7 +134,7 @@ export interface ActAnswer<K extends string = string, A extends string = string>
|
|
|
122
134
|
max_error?: string;
|
|
123
135
|
deferred?: boolean;
|
|
124
136
|
}
|
|
125
|
-
export type Answer = ChoiceAnswer | NoulAnswer | ScoreAnswer | MultiAnswer | ActAnswer | ToolAnswer;
|
|
137
|
+
export type Answer = ChoiceAnswer | NoulAnswer | ScoreAnswer | MultiAnswer | ActAnswer | ToolAnswer | TaskAnswer;
|
|
126
138
|
export interface Usage {
|
|
127
139
|
input_tokens: number;
|
|
128
140
|
output_tokens: number;
|
package/dist/esm/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { buildRequest } from "./questions.js";
|
|
2
2
|
export * from "./questions.js";
|
|
3
3
|
export * from "./media.js";
|
|
4
|
+
export * from "./tasks.js";
|
|
4
5
|
export class BasalError extends Error {
|
|
5
6
|
}
|
|
6
7
|
/** Non-2xx response. Server body and Retry-After are available without logging them. */
|
package/dist/esm/questions.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ export interface ToolOptions extends MultiOptions {
|
|
|
33
33
|
rank?: number;
|
|
34
34
|
multi?: boolean;
|
|
35
35
|
max_error?: number;
|
|
36
|
+
/** Tool-description truncation cap; omitted keeps the server default (300), zero disables truncation. */
|
|
37
|
+
description_chars?: number;
|
|
36
38
|
}
|
|
37
39
|
export interface ActOptions<K extends string = string, A extends string = string> extends EvidenceOptions {
|
|
38
40
|
criteria?: Record<K, string>;
|
package/dist/esm/questions.js
CHANGED
|
@@ -30,13 +30,13 @@ function evidence(options) {
|
|
|
30
30
|
export class QuestionSpec {
|
|
31
31
|
wire;
|
|
32
32
|
constructor(kind, instructions, fields) {
|
|
33
|
-
this.wire = structuredClone({ ...fields, type: kind, instructions: text(instructions, 'instructions') });
|
|
33
|
+
this.wire = structuredClone({ ...fields, type: kind, ...(['classify', 'verify', 'compress', 'extract'].includes(kind) ? (instructions ? { instructions } : {}) : { instructions: text(instructions, 'instructions') }) });
|
|
34
34
|
}
|
|
35
35
|
toJSON() { return structuredClone(this.wire); }
|
|
36
36
|
/** Validate and retrieve an answer with this question's result type. */
|
|
37
37
|
read(response, id) {
|
|
38
38
|
const answer = response.answers?.[id];
|
|
39
|
-
if (!answer || answer.type !== this.wire.type || !answer.probabilities || typeof answer.probabilities !== 'object' || Array.isArray(answer.probabilities)) {
|
|
39
|
+
if (!answer || !('probabilities' in answer) || answer.type !== this.wire.type || !answer.probabilities || typeof answer.probabilities !== 'object' || Array.isArray(answer.probabilities)) {
|
|
40
40
|
throw new TypeError('Basal returned a missing or mismatched answer');
|
|
41
41
|
}
|
|
42
42
|
const fields = {
|
|
@@ -201,6 +201,11 @@ export class ToolQuestion extends QuestionSpec {
|
|
|
201
201
|
if (options.multi !== undefined && typeof options.multi !== 'boolean')
|
|
202
202
|
throw new TypeError('invalid multi');
|
|
203
203
|
const fields = { tools, ...(options.extra === undefined ? {} : { extra: options.extra }) };
|
|
204
|
+
if (options.description_chars !== undefined) {
|
|
205
|
+
if (!Number.isSafeInteger(options.description_chars) || options.description_chars < 0)
|
|
206
|
+
throw new TypeError('description_chars must be a non-negative safe integer');
|
|
207
|
+
fields.description_chars = options.description_chars;
|
|
208
|
+
}
|
|
204
209
|
if (options.rank !== undefined) {
|
|
205
210
|
if (!Number.isSafeInteger(options.rank) || options.rank < 1)
|
|
206
211
|
throw new TypeError('rank must be a positive integer');
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { QuestionSpec } from './questions.js';
|
|
2
|
+
import type { DecisionResponse, JsonValue, Question, MultiObjective } from './index.js';
|
|
3
|
+
/** Task automation is unknown (null) without a threshold certified for that task/error target. */
|
|
4
|
+
export type Automation = Record<string, boolean | null>;
|
|
5
|
+
export interface ClassifyAnswer<K extends string = string> {
|
|
6
|
+
type: 'classify';
|
|
7
|
+
experimental: true;
|
|
8
|
+
scores: Record<K, number>;
|
|
9
|
+
label?: K;
|
|
10
|
+
top_label?: K;
|
|
11
|
+
confidence?: number;
|
|
12
|
+
automated?: Automation;
|
|
13
|
+
labels?: K[];
|
|
14
|
+
set_confidence?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface ClaimResult {
|
|
17
|
+
verdict: 'supported' | 'contradicted' | 'not_stated' | 'not_supported';
|
|
18
|
+
probabilities: Record<string, number>;
|
|
19
|
+
confidence: number;
|
|
20
|
+
automated: Automation;
|
|
21
|
+
}
|
|
22
|
+
export interface VerifyAnswer {
|
|
23
|
+
type: 'verify';
|
|
24
|
+
experimental: true;
|
|
25
|
+
claims: Record<string, ClaimResult>;
|
|
26
|
+
all_supported: boolean;
|
|
27
|
+
not_supported: string[];
|
|
28
|
+
}
|
|
29
|
+
/** Inclusive start/exclusive end count Unicode code points, not JavaScript UTF-16 units. */
|
|
30
|
+
export interface CompressionUnit {
|
|
31
|
+
start: number;
|
|
32
|
+
end: number;
|
|
33
|
+
probability: number;
|
|
34
|
+
}
|
|
35
|
+
export interface CompressAnswer {
|
|
36
|
+
type: 'compress';
|
|
37
|
+
experimental: true;
|
|
38
|
+
compressed: string;
|
|
39
|
+
kept: number[];
|
|
40
|
+
units: CompressionUnit[];
|
|
41
|
+
unit: 'sentence' | 'line' | 'paragraph';
|
|
42
|
+
original_chars: number;
|
|
43
|
+
compressed_chars: number;
|
|
44
|
+
ratio: number;
|
|
45
|
+
}
|
|
46
|
+
export interface ExtractField {
|
|
47
|
+
value: JsonValue;
|
|
48
|
+
confidence: number;
|
|
49
|
+
source: 'choice' | 'span';
|
|
50
|
+
calibration: 'validated' | 'per decision';
|
|
51
|
+
probabilities?: Record<string, number>;
|
|
52
|
+
present_probability?: number;
|
|
53
|
+
text?: string;
|
|
54
|
+
start?: number;
|
|
55
|
+
end?: number;
|
|
56
|
+
line_probability?: number;
|
|
57
|
+
span_probability?: number;
|
|
58
|
+
error?: string;
|
|
59
|
+
}
|
|
60
|
+
export interface ExtractAnswer {
|
|
61
|
+
type: 'extract';
|
|
62
|
+
experimental: true;
|
|
63
|
+
data: Record<string, JsonValue>;
|
|
64
|
+
fields: Record<string, ExtractField>;
|
|
65
|
+
}
|
|
66
|
+
export type TaskAnswer = ClassifyAnswer | VerifyAnswer | CompressAnswer | ExtractAnswer;
|
|
67
|
+
export interface ClassifyOptions {
|
|
68
|
+
multi_label?: boolean;
|
|
69
|
+
none?: boolean;
|
|
70
|
+
max_error?: number | readonly number[];
|
|
71
|
+
option_keys?: 'show' | 'hide';
|
|
72
|
+
threshold?: number;
|
|
73
|
+
min?: number;
|
|
74
|
+
max?: number;
|
|
75
|
+
objective?: MultiObjective;
|
|
76
|
+
}
|
|
77
|
+
export interface VerifyOptions {
|
|
78
|
+
binary?: boolean;
|
|
79
|
+
max_error?: number | readonly number[];
|
|
80
|
+
}
|
|
81
|
+
export interface CompressOptions {
|
|
82
|
+
unit?: 'sentence' | 'line' | 'paragraph';
|
|
83
|
+
keep_ratio?: number;
|
|
84
|
+
threshold?: number;
|
|
85
|
+
min_keep?: number;
|
|
86
|
+
}
|
|
87
|
+
declare abstract class TaskQuestion<A extends TaskAnswer> extends QuestionSpec<A> {
|
|
88
|
+
protected constructor(kind: A['type'], text: string, fields: Question);
|
|
89
|
+
read(response: DecisionResponse, id: string): A;
|
|
90
|
+
}
|
|
91
|
+
export declare class ClassifyQuestion<K extends string = string> extends TaskQuestion<ClassifyAnswer<K>> {
|
|
92
|
+
constructor(text: string, labels: Record<K, JsonValue> | readonly JsonValue[], options?: ClassifyOptions);
|
|
93
|
+
}
|
|
94
|
+
export declare class VerifyQuestion extends TaskQuestion<VerifyAnswer> {
|
|
95
|
+
constructor(text: string, claims: Record<string, JsonValue> | readonly JsonValue[], options?: VerifyOptions);
|
|
96
|
+
}
|
|
97
|
+
export declare class CompressQuestion extends TaskQuestion<CompressAnswer> {
|
|
98
|
+
constructor(text?: string, options?: CompressOptions);
|
|
99
|
+
}
|
|
100
|
+
export declare class ExtractQuestion extends TaskQuestion<ExtractAnswer> {
|
|
101
|
+
constructor(text: string, schema: Record<string, JsonValue>);
|
|
102
|
+
}
|
|
103
|
+
export declare function classify<const K extends string>(text: string, labels: Record<K, JsonValue>, options?: ClassifyOptions): ClassifyQuestion<K>;
|
|
104
|
+
export declare function classify(text: string, labels: readonly JsonValue[], options?: ClassifyOptions): ClassifyQuestion;
|
|
105
|
+
export declare function verify(text: string, claims: Record<string, JsonValue> | readonly JsonValue[], options?: VerifyOptions): VerifyQuestion;
|
|
106
|
+
export declare function compress(text?: string, options?: CompressOptions): CompressQuestion;
|
|
107
|
+
export declare function extract(text: string, schema: Record<string, JsonValue>): ExtractQuestion;
|
|
108
|
+
export {};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { QuestionSpec } from './questions.js';
|
|
2
|
+
function object(v) {
|
|
3
|
+
if (!v || typeof v !== 'object' || Array.isArray(v))
|
|
4
|
+
throw new TypeError('expected task object');
|
|
5
|
+
return v;
|
|
6
|
+
}
|
|
7
|
+
function probability(v) { if (typeof v !== 'number' || !Number.isFinite(v) || v < 0 || v > 1)
|
|
8
|
+
throw new TypeError('invalid probability'); }
|
|
9
|
+
function probabilities(v) { for (const n of Object.values(object(v)))
|
|
10
|
+
probability(n); }
|
|
11
|
+
function automation(v) { if (Object.values(object(v)).some(n => n !== null && typeof n !== 'boolean'))
|
|
12
|
+
throw new TypeError('invalid automation'); }
|
|
13
|
+
function strings(v) { if (!Array.isArray(v) || v.some(k => typeof k !== 'string'))
|
|
14
|
+
throw new TypeError('expected string list'); }
|
|
15
|
+
function offset(v) { if (!Number.isSafeInteger(v) || v < 0)
|
|
16
|
+
throw new TypeError('invalid Unicode code point offset/count'); }
|
|
17
|
+
function span(v) { offset(v.start); offset(v.end); if (v.end < v.start)
|
|
18
|
+
throw new TypeError('reversed source span'); }
|
|
19
|
+
function risks(v) {
|
|
20
|
+
if (v === undefined)
|
|
21
|
+
return;
|
|
22
|
+
const a = Array.isArray(v) ? v : [v];
|
|
23
|
+
if (a.length > 64 || a.some(n => typeof n !== 'number' || !Number.isFinite(n) || n <= 0 || n >= 1))
|
|
24
|
+
throw new TypeError('invalid max_error');
|
|
25
|
+
}
|
|
26
|
+
function instructions(v) { if (typeof v !== 'string')
|
|
27
|
+
throw new TypeError('instructions must be a string'); return v; }
|
|
28
|
+
class TaskQuestion extends QuestionSpec {
|
|
29
|
+
constructor(kind, text, fields) { super(kind, instructions(text), fields); }
|
|
30
|
+
read(response, id) {
|
|
31
|
+
const d = object(response.answers?.[id]);
|
|
32
|
+
if (d.type !== this.toJSON().type || d.experimental !== true)
|
|
33
|
+
throw new TypeError('Basal returned a missing or mismatched task');
|
|
34
|
+
if (d.type === 'classify') {
|
|
35
|
+
probabilities(d.scores);
|
|
36
|
+
const scores = object(d.scores);
|
|
37
|
+
if (this.toJSON().multi_label) {
|
|
38
|
+
strings(d.labels);
|
|
39
|
+
if (d.labels.some(k => !Object.hasOwn(scores, k)))
|
|
40
|
+
throw new TypeError('unknown label');
|
|
41
|
+
probability(d.set_confidence);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
if (typeof d.label !== 'string' || !Object.hasOwn(scores, d.label) || d.top_label !== d.label)
|
|
45
|
+
throw new TypeError('invalid label');
|
|
46
|
+
probability(d.confidence);
|
|
47
|
+
automation(d.automated);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else if (d.type === 'verify') {
|
|
51
|
+
const claims = object(d.claims);
|
|
52
|
+
for (const raw of Object.values(claims)) {
|
|
53
|
+
const c = object(raw);
|
|
54
|
+
const p = object(c.probabilities);
|
|
55
|
+
probabilities(p);
|
|
56
|
+
if (typeof c.verdict !== 'string' || !['supported', 'contradicted', 'not_stated', 'not_supported'].includes(c.verdict) || !Object.hasOwn(p, c.verdict))
|
|
57
|
+
throw new TypeError('invalid verdict');
|
|
58
|
+
probability(c.confidence);
|
|
59
|
+
automation(c.automated);
|
|
60
|
+
}
|
|
61
|
+
strings(d.not_supported);
|
|
62
|
+
if (typeof d.all_supported !== 'boolean' || d.not_supported.some(k => !Object.hasOwn(claims, k)))
|
|
63
|
+
throw new TypeError('invalid verification summary');
|
|
64
|
+
}
|
|
65
|
+
else if (d.type === 'compress') {
|
|
66
|
+
if (typeof d.compressed !== 'string' || !['sentence', 'line', 'paragraph'].includes(d.unit) || !Array.isArray(d.units) || !Array.isArray(d.kept))
|
|
67
|
+
throw new TypeError('invalid compression');
|
|
68
|
+
for (const u of d.units) {
|
|
69
|
+
const v = object(u);
|
|
70
|
+
span(v);
|
|
71
|
+
probability(v.probability);
|
|
72
|
+
}
|
|
73
|
+
for (const k of d.kept) {
|
|
74
|
+
offset(k);
|
|
75
|
+
if (k >= d.units.length)
|
|
76
|
+
throw new TypeError('invalid kept unit');
|
|
77
|
+
}
|
|
78
|
+
offset(d.original_chars);
|
|
79
|
+
offset(d.compressed_chars);
|
|
80
|
+
if (typeof d.ratio !== 'number' || !Number.isFinite(d.ratio) || d.ratio < 0)
|
|
81
|
+
throw new TypeError('invalid ratio');
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
object(d.data);
|
|
85
|
+
for (const raw of Object.values(object(d.fields))) {
|
|
86
|
+
const f = object(raw);
|
|
87
|
+
if (!Object.hasOwn(f, 'value') || !['choice', 'span'].includes(f.source) || !['validated', 'per decision'].includes(f.calibration))
|
|
88
|
+
throw new TypeError('invalid extraction field');
|
|
89
|
+
probability(f.confidence);
|
|
90
|
+
if (f.probabilities !== undefined)
|
|
91
|
+
probabilities(f.probabilities);
|
|
92
|
+
for (const k of ['present_probability', 'line_probability', 'span_probability'])
|
|
93
|
+
if (f[k] !== undefined)
|
|
94
|
+
probability(f[k]);
|
|
95
|
+
if (f.text !== undefined) {
|
|
96
|
+
if (typeof f.text !== 'string')
|
|
97
|
+
throw new TypeError('invalid source text');
|
|
98
|
+
span(f);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return structuredClone(d);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export class ClassifyQuestion extends TaskQuestion {
|
|
106
|
+
constructor(text, labels, options = {}) {
|
|
107
|
+
if (!labels || typeof labels !== 'object' || Object.keys(labels).length < 1 || Object.keys(labels).length > 256)
|
|
108
|
+
throw new TypeError('classify requires 1..256 labels');
|
|
109
|
+
risks(options.max_error);
|
|
110
|
+
for (const k of ['multi_label', 'none'])
|
|
111
|
+
if (options[k] !== undefined && typeof options[k] !== 'boolean')
|
|
112
|
+
throw new TypeError(`invalid ${k}`);
|
|
113
|
+
if (options.option_keys !== undefined && !['show', 'hide'].includes(options.option_keys))
|
|
114
|
+
throw new TypeError('invalid option_keys');
|
|
115
|
+
if (options.threshold !== undefined) {
|
|
116
|
+
probability(options.threshold);
|
|
117
|
+
if (options.objective !== undefined && options.objective !== 'threshold')
|
|
118
|
+
throw new TypeError('threshold requires threshold objective');
|
|
119
|
+
}
|
|
120
|
+
for (const k of ['min', 'max'])
|
|
121
|
+
if (options[k] !== undefined)
|
|
122
|
+
offset(options[k]);
|
|
123
|
+
if (options.min !== undefined && options.max !== undefined && options.min > options.max)
|
|
124
|
+
throw new TypeError('min exceeds max');
|
|
125
|
+
if (options.objective !== undefined && !['threshold', 'exact', 'iou', 'f1'].includes(options.objective))
|
|
126
|
+
throw new TypeError('invalid objective');
|
|
127
|
+
if (!options.multi_label && ['threshold', 'min', 'max', 'objective'].some(k => Object.hasOwn(options, k)))
|
|
128
|
+
throw new TypeError('selection options require multi_label');
|
|
129
|
+
super('classify', text, { labels: structuredClone(labels), ...options });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
export class VerifyQuestion extends TaskQuestion {
|
|
133
|
+
constructor(text, claims, options = {}) {
|
|
134
|
+
if (!claims || typeof claims !== 'object' || !Object.keys(claims).length)
|
|
135
|
+
throw new TypeError('verify requires claims');
|
|
136
|
+
risks(options.max_error);
|
|
137
|
+
if (options.binary !== undefined && typeof options.binary !== 'boolean')
|
|
138
|
+
throw new TypeError('invalid binary');
|
|
139
|
+
super('verify', text, { claims: structuredClone(claims), ...options });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
export class CompressQuestion extends TaskQuestion {
|
|
143
|
+
constructor(text = '', options = {}) {
|
|
144
|
+
if (options.unit !== undefined && !['sentence', 'line', 'paragraph'].includes(options.unit))
|
|
145
|
+
throw new TypeError('invalid unit');
|
|
146
|
+
if (options.keep_ratio !== undefined) {
|
|
147
|
+
probability(options.keep_ratio);
|
|
148
|
+
if (options.keep_ratio === 0)
|
|
149
|
+
throw new TypeError('keep_ratio must be positive');
|
|
150
|
+
}
|
|
151
|
+
if (options.threshold !== undefined)
|
|
152
|
+
probability(options.threshold);
|
|
153
|
+
if (options.min_keep !== undefined)
|
|
154
|
+
offset(options.min_keep);
|
|
155
|
+
super('compress', text, options);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
export class ExtractQuestion extends TaskQuestion {
|
|
159
|
+
constructor(text, schema) { object(schema); super('extract', text, { schema }); }
|
|
160
|
+
}
|
|
161
|
+
export function classify(text, labels, options) { return new ClassifyQuestion(text, labels, options); }
|
|
162
|
+
export function verify(text, claims, options) { return new VerifyQuestion(text, claims, options); }
|
|
163
|
+
export function compress(text = '', options) { return new CompressQuestion(text, options); }
|
|
164
|
+
export function extract(text, schema) { return new ExtractQuestion(text, schema); }
|