@toloka-platform/sdk 0.1.0-preview.3 → 0.1.0-preview.5
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 +2 -2
- package/bin/toloka.js +7 -0
- package/dist/cli/toloka.js +119 -114
- package/dist/cli/toloka.js.jsc +0 -0
- package/dist/cli/toloka.js.jsc.sha256 +1 -1
- package/dist/cli/toloka.js.sha256 +1 -1
- package/docs/cli-v2.md +4 -0
- package/docs/cli.md +56 -5
- package/docs/getting-started.md +3 -3
- package/docs/limitations.md +1 -1
- package/openapi/gen/api.ts +22 -0
- package/openapi/gen/models/createDatasetBody.ts +2 -0
- package/openapi/gen/models/createDatasetBodyProfile.ts +2 -0
- package/openapi/gen/models/createDatasetUploadBodyFormat.ts +1 -1
- package/openapi/gen/models/dataset.ts +2 -0
- package/openapi/gen/models/datasetProfile.ts +3 -0
- package/openapi/gen/models/datasetProfileStamp.ts +6 -0
- package/openapi/gen/models/datasetProfileStampName.ts +2 -0
- package/openapi/gen/models/index.ts +5 -0
- package/openapi/gen/models/runCost.ts +7 -0
- package/package.json +4 -2
- package/skills/catalog.json +22 -0
- package/skills/{SKILL.md → toloka-build/SKILL.md} +1 -1
- package/skills/{references → toloka-build/references}/workflow-and-cli.md +14 -4
- package/skills/toloka-report-issue/SKILL.md +25 -0
- package/skills/toloka-report-issue/references/report-template.md +34 -0
- package/src/authoring/index.ts +216 -171
- package/src/cli/analytics.ts +53 -1
- package/src/cli/auth.ts +5 -5
- package/src/cli/credentials.ts +8 -2
- package/src/cli/file-system.ts +34 -0
- package/src/cli/format-error.ts +19 -0
- package/src/cli/init.ts +149 -194
- package/src/cli/program.ts +103 -21
- package/src/cli/report.ts +144 -0
- package/src/cli/skill.ts +363 -0
- package/src/pipeline-graph-v1.contract.json +5 -1
- /package/skills/{references → toloka-build/references}/node-semantics.md +0 -0
package/src/authoring/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { assert } from
|
|
1
|
+
import { assert } from "es-toolkit";
|
|
2
2
|
import type {
|
|
3
3
|
CodeNode,
|
|
4
4
|
CodeNodeSettings,
|
|
@@ -11,14 +11,14 @@ import type {
|
|
|
11
11
|
QuorumNode,
|
|
12
12
|
QuorumNodeSettings,
|
|
13
13
|
RootNode,
|
|
14
|
-
RootNodeSettings
|
|
15
|
-
} from
|
|
16
|
-
import { validate } from
|
|
14
|
+
RootNodeSettings,
|
|
15
|
+
} from "../../openapi/gen/models";
|
|
16
|
+
import { validate } from "../validate";
|
|
17
17
|
|
|
18
|
-
const FIELD_DEFINITION = Symbol(
|
|
19
|
-
const PIPELINE_DEFINITION = Symbol(
|
|
20
|
-
const PORT_DEFINITION = Symbol(
|
|
21
|
-
const NODE_FIELD_REFERENCES = Symbol(
|
|
18
|
+
const FIELD_DEFINITION = Symbol("fieldDefinition");
|
|
19
|
+
const PIPELINE_DEFINITION = Symbol.for("@toloka-platform/sdk/pipeline-definition");
|
|
20
|
+
const PORT_DEFINITION = Symbol("portDefinition");
|
|
21
|
+
const NODE_FIELD_REFERENCES = Symbol("nodeFieldReferences");
|
|
22
22
|
|
|
23
23
|
export interface Field<Name extends string = string> {
|
|
24
24
|
readonly id: string;
|
|
@@ -34,21 +34,21 @@ export type AuthoringIdOptions = {
|
|
|
34
34
|
export interface InputPort {
|
|
35
35
|
readonly node: string;
|
|
36
36
|
readonly handle: string;
|
|
37
|
-
readonly direction:
|
|
38
|
-
readonly [PORT_DEFINITION]:
|
|
37
|
+
readonly direction: "input";
|
|
38
|
+
readonly [PORT_DEFINITION]: "input";
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export interface OutputPort {
|
|
42
42
|
readonly node: string;
|
|
43
43
|
readonly handle: string;
|
|
44
|
-
readonly direction:
|
|
45
|
-
readonly [PORT_DEFINITION]:
|
|
44
|
+
readonly direction: "output";
|
|
45
|
+
readonly [PORT_DEFINITION]: "output";
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
export interface Connection {
|
|
49
49
|
readonly from: OutputPort;
|
|
50
50
|
readonly to: InputPort;
|
|
51
|
-
readonly settings: PipelineGraphV1[
|
|
51
|
+
readonly settings: PipelineGraphV1["connections"][number]["settings"];
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
type FieldProxyReference = {
|
|
@@ -59,12 +59,13 @@ type FieldProxyReference = {
|
|
|
59
59
|
type RootFieldReference = Field | { readonly field: Field; readonly optional?: boolean };
|
|
60
60
|
|
|
61
61
|
type FieldRelation<Relation> = Relation extends { id: string }
|
|
62
|
-
? Omit<Relation,
|
|
62
|
+
? Omit<Relation, "id"> & { readonly field: Field }
|
|
63
63
|
: never;
|
|
64
64
|
|
|
65
|
-
type FieldRelations<Relations> =
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
type FieldRelations<Relations> =
|
|
66
|
+
NonNullable<Relations> extends Array<infer Relation>
|
|
67
|
+
? ReadonlyArray<FieldRelation<Relation>>
|
|
68
|
+
: never;
|
|
68
69
|
|
|
69
70
|
type FieldEntity<Entity> = Entity extends {
|
|
70
71
|
fieldProxyId: string;
|
|
@@ -74,7 +75,7 @@ type FieldEntity<Entity> = Entity extends {
|
|
|
74
75
|
relations?: infer Relations;
|
|
75
76
|
dynamic: true;
|
|
76
77
|
}
|
|
77
|
-
? Omit<Entity,
|
|
78
|
+
? Omit<Entity, "fieldProxyId" | "optional" | "jsonPath" | "description" | "relations"> & {
|
|
78
79
|
readonly field: Field;
|
|
79
80
|
readonly optional?: boolean;
|
|
80
81
|
readonly jsonPath?: string;
|
|
@@ -89,7 +90,10 @@ type FieldEntity<Entity> = Entity extends {
|
|
|
89
90
|
relations?: infer Relations;
|
|
90
91
|
dynamic: false;
|
|
91
92
|
}
|
|
92
|
-
? Omit<
|
|
93
|
+
? Omit<
|
|
94
|
+
Entity,
|
|
95
|
+
"fieldProxyId" | "optional" | "jsonPath" | "description" | "relations" | "dynamic"
|
|
96
|
+
> & {
|
|
93
97
|
readonly field: Field;
|
|
94
98
|
readonly optional?: boolean;
|
|
95
99
|
readonly jsonPath?: string;
|
|
@@ -100,36 +104,42 @@ type FieldEntity<Entity> = Entity extends {
|
|
|
100
104
|
: never;
|
|
101
105
|
|
|
102
106
|
type FieldTarget<Target> = Target extends { targetEntity: string }
|
|
103
|
-
? Omit<Target,
|
|
107
|
+
? Omit<Target, "targetEntity"> & { readonly targetEntity: Field }
|
|
104
108
|
: never;
|
|
105
109
|
|
|
106
|
-
type FieldExam<Exam extends { gradedEntities: Array<{ targetEntity: string }> }> = Omit<
|
|
107
|
-
|
|
110
|
+
type FieldExam<Exam extends { gradedEntities: Array<{ targetEntity: string }> }> = Omit<
|
|
111
|
+
Exam,
|
|
112
|
+
"gradedEntities"
|
|
113
|
+
> & {
|
|
114
|
+
readonly gradedEntities: ReadonlyArray<FieldTarget<Exam["gradedEntities"][number]>>;
|
|
108
115
|
};
|
|
109
116
|
|
|
110
|
-
type GenerationInputEntity = FieldEntity<GenerationNodeSettings[
|
|
111
|
-
type GenerationOutputEntity = FieldEntity<GenerationNodeSettings[
|
|
112
|
-
type GenerationQualityCriterion = FieldTarget<GenerationNodeSettings[
|
|
113
|
-
type GenerationExam = FieldExam<NonNullable<GenerationNodeSettings[
|
|
117
|
+
type GenerationInputEntity = FieldEntity<GenerationNodeSettings["entities"]["input"][number]>;
|
|
118
|
+
type GenerationOutputEntity = FieldEntity<GenerationNodeSettings["entities"]["output"][number]>;
|
|
119
|
+
type GenerationQualityCriterion = FieldTarget<GenerationNodeSettings["qualityCriteria"][number]>;
|
|
120
|
+
type GenerationExam = FieldExam<NonNullable<GenerationNodeSettings["exam"]>>;
|
|
114
121
|
|
|
115
|
-
type QuorumInputEntity = FieldEntity<QuorumNodeSettings[
|
|
116
|
-
type QuorumOutputEntity = FieldEntity<QuorumNodeSettings[
|
|
117
|
-
type QuorumQualityCriterion = FieldTarget<QuorumNodeSettings[
|
|
118
|
-
type QuorumExam = FieldExam<NonNullable<QuorumNodeSettings[
|
|
122
|
+
type QuorumInputEntity = FieldEntity<QuorumNodeSettings["entities"]["input"][number]>;
|
|
123
|
+
type QuorumOutputEntity = FieldEntity<QuorumNodeSettings["entities"]["output"][number]>;
|
|
124
|
+
type QuorumQualityCriterion = FieldTarget<QuorumNodeSettings["qualityCriteria"][number]>;
|
|
125
|
+
type QuorumExam = FieldExam<NonNullable<QuorumNodeSettings["exam"]>>;
|
|
119
126
|
|
|
120
|
-
type MatchPredicate = Omit<
|
|
127
|
+
type MatchPredicate = Omit<
|
|
128
|
+
MatchNodeSettings["conditions"][number]["predicates"][number],
|
|
129
|
+
"fieldProxyId"
|
|
130
|
+
> & {
|
|
121
131
|
readonly field: Field;
|
|
122
132
|
};
|
|
123
133
|
|
|
124
134
|
export type RootAuthoringSettings = Omit<
|
|
125
135
|
RootNodeSettings,
|
|
126
|
-
|
|
136
|
+
"datasetId" | "itemFilter" | "startedFieldProxies" | "completedFieldProxies"
|
|
127
137
|
> & {
|
|
128
138
|
readonly started: ReadonlyArray<RootFieldReference>;
|
|
129
139
|
readonly completed: ReadonlyArray<RootFieldReference>;
|
|
130
140
|
};
|
|
131
141
|
|
|
132
|
-
export type CodeAuthoringSettings = Omit<CodeNodeSettings,
|
|
142
|
+
export type CodeAuthoringSettings = Omit<CodeNodeSettings, "fieldProxies"> & {
|
|
133
143
|
readonly fieldProxies: {
|
|
134
144
|
readonly input: ReadonlyArray<FieldProxyReference>;
|
|
135
145
|
readonly output: ReadonlyArray<FieldProxyReference>;
|
|
@@ -138,23 +148,23 @@ export type CodeAuthoringSettings = Omit<CodeNodeSettings, 'fieldProxies'> & {
|
|
|
138
148
|
|
|
139
149
|
export type GenerationAuthoringSettings = Omit<
|
|
140
150
|
GenerationNodeSettings,
|
|
141
|
-
|
|
151
|
+
"about" | "entities" | "qualityCriteria" | "instruction" | "ui" | "onboarding" | "exam"
|
|
142
152
|
> & {
|
|
143
|
-
readonly about?: Omit<GenerationNodeSettings[
|
|
153
|
+
readonly about?: Omit<GenerationNodeSettings["about"], "name"> & { readonly name?: string };
|
|
144
154
|
readonly entities: {
|
|
145
155
|
readonly input: ReadonlyArray<GenerationInputEntity>;
|
|
146
156
|
readonly output: ReadonlyArray<GenerationOutputEntity>;
|
|
147
157
|
};
|
|
148
158
|
readonly qualityCriteria?: ReadonlyArray<GenerationQualityCriterion>;
|
|
149
159
|
readonly instruction?: string;
|
|
150
|
-
readonly ui?: GenerationNodeSettings[
|
|
151
|
-
readonly onboarding?: GenerationNodeSettings[
|
|
160
|
+
readonly ui?: GenerationNodeSettings["ui"];
|
|
161
|
+
readonly onboarding?: GenerationNodeSettings["onboarding"];
|
|
152
162
|
readonly exam?: GenerationExam;
|
|
153
163
|
};
|
|
154
164
|
|
|
155
|
-
export type MatchAuthoringSettings = Omit<MatchNodeSettings,
|
|
165
|
+
export type MatchAuthoringSettings = Omit<MatchNodeSettings, "conditions" | "fieldProxies"> & {
|
|
156
166
|
readonly conditions: ReadonlyArray<
|
|
157
|
-
Omit<MatchNodeSettings[
|
|
167
|
+
Omit<MatchNodeSettings["conditions"][number], "predicates"> & {
|
|
158
168
|
readonly predicates: ReadonlyArray<MatchPredicate>;
|
|
159
169
|
}
|
|
160
170
|
>;
|
|
@@ -163,7 +173,10 @@ export type MatchAuthoringSettings = Omit<MatchNodeSettings, 'conditions' | 'fie
|
|
|
163
173
|
};
|
|
164
174
|
};
|
|
165
175
|
|
|
166
|
-
export type QuorumAuthoringSettings = Omit<
|
|
176
|
+
export type QuorumAuthoringSettings = Omit<
|
|
177
|
+
QuorumNodeSettings,
|
|
178
|
+
"entities" | "qualityCriteria" | "exam"
|
|
179
|
+
> & {
|
|
167
180
|
readonly entities: {
|
|
168
181
|
readonly input: ReadonlyArray<QuorumInputEntity>;
|
|
169
182
|
readonly output: ReadonlyArray<QuorumOutputEntity>;
|
|
@@ -172,17 +185,19 @@ export type QuorumAuthoringSettings = Omit<QuorumNodeSettings, 'entities' | 'qua
|
|
|
172
185
|
readonly exam?: QuorumExam;
|
|
173
186
|
};
|
|
174
187
|
|
|
175
|
-
type WireNode = PipelineGraphV1[
|
|
188
|
+
type WireNode = PipelineGraphV1["nodes"][number];
|
|
176
189
|
|
|
177
|
-
interface AuthoredNode<Node extends WireNode, Settings = Node[
|
|
190
|
+
interface AuthoredNode<Node extends WireNode, Settings = Node["settings"]> {
|
|
178
191
|
readonly id: string;
|
|
179
|
-
readonly type: Node[
|
|
192
|
+
readonly type: Node["type"];
|
|
180
193
|
readonly settings: Settings;
|
|
181
194
|
readonly [NODE_FIELD_REFERENCES]: ReadonlyArray<Field>;
|
|
182
195
|
}
|
|
183
196
|
|
|
184
|
-
export interface AuthoredRootNode
|
|
185
|
-
|
|
197
|
+
export interface AuthoredRootNode extends AuthoredNode<
|
|
198
|
+
RootNode,
|
|
199
|
+
Omit<RootNodeSettings, "datasetId" | "itemFilter">
|
|
200
|
+
> {
|
|
186
201
|
readonly started: OutputPort;
|
|
187
202
|
readonly completed: InputPort;
|
|
188
203
|
}
|
|
@@ -215,15 +230,15 @@ export type PipelineNode =
|
|
|
215
230
|
| AuthoredMatchNode
|
|
216
231
|
| AuthoredQuorumNode;
|
|
217
232
|
|
|
218
|
-
type UnboundRootNode = Omit<RootNode,
|
|
219
|
-
readonly settings: Omit<RootNodeSettings,
|
|
233
|
+
type UnboundRootNode = Omit<RootNode, "settings"> & {
|
|
234
|
+
readonly settings: Omit<RootNodeSettings, "datasetId" | "itemFilter">;
|
|
220
235
|
};
|
|
221
236
|
|
|
222
237
|
export type UnboundPipelineGraphV1 = {
|
|
223
238
|
readonly version: 1;
|
|
224
|
-
readonly fields: ReadonlyArray<PipelineGraphV1[
|
|
239
|
+
readonly fields: ReadonlyArray<PipelineGraphV1["fields"][number]>;
|
|
225
240
|
readonly nodes: ReadonlyArray<UnboundRootNode | Exclude<WireNode, RootNode>>;
|
|
226
|
-
readonly connections: ReadonlyArray<PipelineGraphV1[
|
|
241
|
+
readonly connections: ReadonlyArray<PipelineGraphV1["connections"][number]>;
|
|
227
242
|
};
|
|
228
243
|
|
|
229
244
|
export type PipelineDefinitionInput<DatasetName extends string = string> = {
|
|
@@ -249,34 +264,36 @@ function hash(value: string): string {
|
|
|
249
264
|
result ^= value.charCodeAt(index);
|
|
250
265
|
result = Math.imul(result, 0x01000193);
|
|
251
266
|
}
|
|
252
|
-
return (result >>> 0).toString(16).padStart(8,
|
|
267
|
+
return (result >>> 0).toString(16).padStart(8, "0");
|
|
253
268
|
}
|
|
254
269
|
|
|
255
270
|
function readableName(name: string): string {
|
|
256
|
-
return
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
271
|
+
return (
|
|
272
|
+
name
|
|
273
|
+
.normalize("NFKD")
|
|
274
|
+
.replace(/[\u0300-\u036f]/g, "")
|
|
275
|
+
.toLowerCase()
|
|
276
|
+
.replace(/[^a-z0-9]+/g, "_")
|
|
277
|
+
.replace(/^_+|_+$/g, "")
|
|
278
|
+
.slice(0, 48) || "unnamed"
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function mintedId(kind: "field" | Exclude<WireNode["type"], "root">, name: string): string {
|
|
283
|
+
const prefix = kind === "field" ? "fp" : kind;
|
|
267
284
|
return `${prefix}_${readableName(name)}_${hash(`${kind}:${name}`)}`;
|
|
268
285
|
}
|
|
269
286
|
|
|
270
287
|
function inputPort(node: string, handle: string): InputPort {
|
|
271
|
-
return { node, handle, direction:
|
|
288
|
+
return { node, handle, direction: "input", [PORT_DEFINITION]: "input" };
|
|
272
289
|
}
|
|
273
290
|
|
|
274
291
|
function outputPort(node: string, handle: string): OutputPort {
|
|
275
|
-
return { node, handle, direction:
|
|
292
|
+
return { node, handle, direction: "output", [PORT_DEFINITION]: "output" };
|
|
276
293
|
}
|
|
277
294
|
|
|
278
295
|
function isField(value: unknown): value is Field {
|
|
279
|
-
return typeof value ===
|
|
296
|
+
return typeof value === "object" && value !== null && FIELD_DEFINITION in value;
|
|
280
297
|
}
|
|
281
298
|
|
|
282
299
|
function collectFieldReferences(value: unknown, references: Field[]): void {
|
|
@@ -288,7 +305,7 @@ function collectFieldReferences(value: unknown, references: Field[]): void {
|
|
|
288
305
|
for (const item of value) collectFieldReferences(item, references);
|
|
289
306
|
return;
|
|
290
307
|
}
|
|
291
|
-
if (typeof value ===
|
|
308
|
+
if (typeof value === "object" && value !== null) {
|
|
292
309
|
for (const item of Object.values(value)) collectFieldReferences(item, references);
|
|
293
310
|
}
|
|
294
311
|
}
|
|
@@ -310,19 +327,21 @@ function compileRootFieldProxy(reference: RootFieldReference): { id: string; opt
|
|
|
310
327
|
}
|
|
311
328
|
|
|
312
329
|
function compileGenerationInputRelation(
|
|
313
|
-
relation: NonNullable<GenerationInputEntity[
|
|
314
|
-
): NonNullable<GenerationNodeSettings[
|
|
330
|
+
relation: NonNullable<GenerationInputEntity["relations"]>[number],
|
|
331
|
+
): NonNullable<GenerationNodeSettings["entities"]["input"][number]["relations"]>[number] {
|
|
315
332
|
const { field: referencedField, ...settings } = relation;
|
|
316
333
|
return { ...settings, id: referencedField.id };
|
|
317
334
|
}
|
|
318
335
|
|
|
319
|
-
function compileGenerationInputEntity(
|
|
336
|
+
function compileGenerationInputEntity(
|
|
337
|
+
entity: GenerationInputEntity,
|
|
338
|
+
): GenerationNodeSettings["entities"]["input"][number] {
|
|
320
339
|
if (entity.dynamic === true) {
|
|
321
340
|
const {
|
|
322
341
|
field: referencedField,
|
|
323
342
|
optional = false,
|
|
324
|
-
jsonPath =
|
|
325
|
-
description =
|
|
343
|
+
jsonPath = "$",
|
|
344
|
+
description = "",
|
|
326
345
|
relations = [],
|
|
327
346
|
...settings
|
|
328
347
|
} = entity;
|
|
@@ -332,14 +351,14 @@ function compileGenerationInputEntity(entity: GenerationInputEntity): Generation
|
|
|
332
351
|
optional,
|
|
333
352
|
jsonPath,
|
|
334
353
|
description,
|
|
335
|
-
relations: relations.map(compileGenerationInputRelation)
|
|
354
|
+
relations: relations.map(compileGenerationInputRelation),
|
|
336
355
|
};
|
|
337
356
|
}
|
|
338
357
|
const {
|
|
339
358
|
field: referencedField,
|
|
340
359
|
optional = false,
|
|
341
|
-
jsonPath =
|
|
342
|
-
description =
|
|
360
|
+
jsonPath = "$",
|
|
361
|
+
description = "",
|
|
343
362
|
relations = [],
|
|
344
363
|
dynamic = false,
|
|
345
364
|
...settings
|
|
@@ -351,51 +370,54 @@ function compileGenerationInputEntity(entity: GenerationInputEntity): Generation
|
|
|
351
370
|
jsonPath,
|
|
352
371
|
description,
|
|
353
372
|
relations: relations.map(compileGenerationInputRelation),
|
|
354
|
-
dynamic
|
|
373
|
+
dynamic,
|
|
355
374
|
};
|
|
356
375
|
}
|
|
357
376
|
|
|
358
|
-
function compileGenerationSettings(
|
|
377
|
+
function compileGenerationSettings(
|
|
378
|
+
name: string,
|
|
379
|
+
settings: GenerationAuthoringSettings,
|
|
380
|
+
): GenerationNodeSettings {
|
|
359
381
|
const { exam, ...settingsWithoutExam } = settings;
|
|
360
382
|
return {
|
|
361
383
|
...settingsWithoutExam,
|
|
362
384
|
about: { ...settings.about, name: settings.about?.name ?? name },
|
|
363
385
|
entities: {
|
|
364
386
|
input: settings.entities.input.map(compileGenerationInputEntity),
|
|
365
|
-
output: settings.entities.output.map(compileGenerationInputEntity)
|
|
387
|
+
output: settings.entities.output.map(compileGenerationInputEntity),
|
|
366
388
|
},
|
|
367
389
|
qualityCriteria: (settings.qualityCriteria ?? []).map((criterion) => ({
|
|
368
390
|
...criterion,
|
|
369
|
-
targetEntity: criterion.targetEntity.id
|
|
391
|
+
targetEntity: criterion.targetEntity.id,
|
|
370
392
|
})),
|
|
371
|
-
instruction: settings.instruction ??
|
|
393
|
+
instruction: settings.instruction ?? "",
|
|
372
394
|
ui: settings.ui ?? {
|
|
373
|
-
code:
|
|
374
|
-
data:
|
|
375
|
-
preprocess:
|
|
376
|
-
postprocess:
|
|
377
|
-
constants:
|
|
395
|
+
code: "<></>",
|
|
396
|
+
data: "{}",
|
|
397
|
+
preprocess: "return {}",
|
|
398
|
+
postprocess: "return {};",
|
|
399
|
+
constants: "{}",
|
|
378
400
|
},
|
|
379
401
|
onboarding: settings.onboarding ?? {
|
|
380
402
|
enabled: true,
|
|
381
403
|
steps: [
|
|
382
404
|
{
|
|
383
|
-
id:
|
|
405
|
+
id: "step-1",
|
|
384
406
|
blocks: [
|
|
385
407
|
{
|
|
386
|
-
id:
|
|
387
|
-
type:
|
|
388
|
-
content: [{ type:
|
|
389
|
-
}
|
|
390
|
-
]
|
|
391
|
-
}
|
|
408
|
+
id: "block-1",
|
|
409
|
+
type: "text",
|
|
410
|
+
content: [{ type: "markdown", value: "Welcome to the onboarding!" }],
|
|
411
|
+
},
|
|
412
|
+
],
|
|
413
|
+
},
|
|
392
414
|
],
|
|
393
415
|
info: {
|
|
394
|
-
estimatedTime:
|
|
395
|
-
role:
|
|
396
|
-
goal:
|
|
397
|
-
successCriteria:
|
|
398
|
-
}
|
|
416
|
+
estimatedTime: "30",
|
|
417
|
+
role: "Annotator",
|
|
418
|
+
goal: "Successfully complete all onboarding steps",
|
|
419
|
+
successCriteria: "Pass quiz, accept terms, and provide valid explanation",
|
|
420
|
+
},
|
|
399
421
|
},
|
|
400
422
|
...(exam === undefined
|
|
401
423
|
? {}
|
|
@@ -404,132 +426,135 @@ function compileGenerationSettings(name: string, settings: GenerationAuthoringSe
|
|
|
404
426
|
...exam,
|
|
405
427
|
gradedEntities: exam.gradedEntities.map((entity) => ({
|
|
406
428
|
...entity,
|
|
407
|
-
targetEntity: entity.targetEntity.id
|
|
408
|
-
}))
|
|
409
|
-
}
|
|
410
|
-
})
|
|
429
|
+
targetEntity: entity.targetEntity.id,
|
|
430
|
+
})),
|
|
431
|
+
},
|
|
432
|
+
}),
|
|
411
433
|
};
|
|
412
434
|
}
|
|
413
435
|
|
|
414
436
|
export function field<const Name extends string>(
|
|
415
437
|
name: Name,
|
|
416
438
|
jsonSchema: JsonSchema,
|
|
417
|
-
options: AuthoringIdOptions = {}
|
|
439
|
+
options: AuthoringIdOptions = {},
|
|
418
440
|
): Field<Name> {
|
|
419
441
|
return {
|
|
420
|
-
id: options.id ?? mintedId(
|
|
442
|
+
id: options.id ?? mintedId("field", name),
|
|
421
443
|
name,
|
|
422
444
|
jsonSchema,
|
|
423
|
-
[FIELD_DEFINITION]: true
|
|
445
|
+
[FIELD_DEFINITION]: true,
|
|
424
446
|
};
|
|
425
447
|
}
|
|
426
448
|
|
|
427
|
-
function createRoot(
|
|
428
|
-
|
|
449
|
+
function createRoot(
|
|
450
|
+
settings: RootAuthoringSettings,
|
|
451
|
+
options: AuthoringIdOptions = {},
|
|
452
|
+
): AuthoredRootNode {
|
|
453
|
+
const id = options.id ?? "root";
|
|
429
454
|
const { started, completed, ...settingsWithoutFieldProxies } = settings;
|
|
430
455
|
return {
|
|
431
456
|
id,
|
|
432
|
-
type:
|
|
457
|
+
type: "root",
|
|
433
458
|
settings: {
|
|
434
459
|
...settingsWithoutFieldProxies,
|
|
435
460
|
startedFieldProxies: { output: started.map(compileRootFieldProxy) },
|
|
436
|
-
completedFieldProxies: { input: completed.map(compileRootFieldProxy) }
|
|
461
|
+
completedFieldProxies: { input: completed.map(compileRootFieldProxy) },
|
|
437
462
|
},
|
|
438
|
-
started: outputPort(id,
|
|
439
|
-
completed: inputPort(id,
|
|
440
|
-
[NODE_FIELD_REFERENCES]: referencedFields(settings)
|
|
463
|
+
started: outputPort(id, "started"),
|
|
464
|
+
completed: inputPort(id, "completed"),
|
|
465
|
+
[NODE_FIELD_REFERENCES]: referencedFields(settings),
|
|
441
466
|
};
|
|
442
467
|
}
|
|
443
468
|
|
|
444
469
|
export const root = Object.assign(createRoot, {
|
|
445
|
-
started: outputPort(
|
|
446
|
-
completed: inputPort(
|
|
470
|
+
started: outputPort("root", "started"),
|
|
471
|
+
completed: inputPort("root", "completed"),
|
|
447
472
|
});
|
|
448
473
|
|
|
449
474
|
export function code(
|
|
450
475
|
name: string,
|
|
451
476
|
settings: CodeAuthoringSettings,
|
|
452
|
-
options: AuthoringIdOptions = {}
|
|
477
|
+
options: AuthoringIdOptions = {},
|
|
453
478
|
): AuthoredCodeNode {
|
|
454
|
-
const id = options.id ?? mintedId(
|
|
479
|
+
const id = options.id ?? mintedId("code", name);
|
|
455
480
|
return {
|
|
456
481
|
id,
|
|
457
|
-
type:
|
|
482
|
+
type: "code",
|
|
458
483
|
settings: {
|
|
459
484
|
...settings,
|
|
460
485
|
fieldProxies: {
|
|
461
486
|
input: settings.fieldProxies.input.map(compileFieldProxy),
|
|
462
|
-
output: settings.fieldProxies.output.map(compileFieldProxy)
|
|
463
|
-
}
|
|
487
|
+
output: settings.fieldProxies.output.map(compileFieldProxy),
|
|
488
|
+
},
|
|
464
489
|
},
|
|
465
|
-
input: inputPort(id,
|
|
466
|
-
output: outputPort(id,
|
|
467
|
-
[NODE_FIELD_REFERENCES]: referencedFields(settings)
|
|
490
|
+
input: inputPort(id, "input"),
|
|
491
|
+
output: outputPort(id, "output"),
|
|
492
|
+
[NODE_FIELD_REFERENCES]: referencedFields(settings),
|
|
468
493
|
};
|
|
469
494
|
}
|
|
470
495
|
|
|
471
496
|
export function generation(
|
|
472
497
|
name: string,
|
|
473
498
|
settings: GenerationAuthoringSettings,
|
|
474
|
-
options: AuthoringIdOptions = {}
|
|
499
|
+
options: AuthoringIdOptions = {},
|
|
475
500
|
): AuthoredGenerationNode {
|
|
476
|
-
const id = options.id ?? mintedId(
|
|
501
|
+
const id = options.id ?? mintedId("generation", name);
|
|
477
502
|
return {
|
|
478
503
|
id,
|
|
479
|
-
type:
|
|
504
|
+
type: "generation",
|
|
480
505
|
settings: compileGenerationSettings(name, settings),
|
|
481
|
-
input: inputPort(id,
|
|
482
|
-
output: outputPort(id,
|
|
483
|
-
[NODE_FIELD_REFERENCES]: referencedFields(settings)
|
|
506
|
+
input: inputPort(id, "input"),
|
|
507
|
+
output: outputPort(id, "output"),
|
|
508
|
+
[NODE_FIELD_REFERENCES]: referencedFields(settings),
|
|
484
509
|
};
|
|
485
510
|
}
|
|
486
511
|
|
|
487
512
|
export function match(
|
|
488
513
|
name: string,
|
|
489
514
|
settings: MatchAuthoringSettings,
|
|
490
|
-
options: AuthoringIdOptions = {}
|
|
515
|
+
options: AuthoringIdOptions = {},
|
|
491
516
|
): AuthoredMatchNode {
|
|
492
|
-
const id = options.id ?? mintedId(
|
|
517
|
+
const id = options.id ?? mintedId("match", name);
|
|
493
518
|
return {
|
|
494
519
|
id,
|
|
495
|
-
type:
|
|
520
|
+
type: "match",
|
|
496
521
|
settings: {
|
|
497
522
|
...settings,
|
|
498
523
|
conditions: settings.conditions.map((condition) => ({
|
|
499
524
|
...condition,
|
|
500
525
|
predicates: condition.predicates.map(({ field: referencedField, ...predicate }) => ({
|
|
501
526
|
...predicate,
|
|
502
|
-
fieldProxyId: referencedField.id
|
|
503
|
-
}))
|
|
527
|
+
fieldProxyId: referencedField.id,
|
|
528
|
+
})),
|
|
504
529
|
})),
|
|
505
|
-
fieldProxies: { input: settings.fieldProxies.input.map(compileFieldProxy) }
|
|
530
|
+
fieldProxies: { input: settings.fieldProxies.input.map(compileFieldProxy) },
|
|
506
531
|
},
|
|
507
|
-
input: inputPort(id,
|
|
508
|
-
default: outputPort(id,
|
|
532
|
+
input: inputPort(id, "input"),
|
|
533
|
+
default: outputPort(id, "default"),
|
|
509
534
|
matched: (index) => outputPort(id, `matched_${index}`),
|
|
510
|
-
[NODE_FIELD_REFERENCES]: referencedFields(settings)
|
|
535
|
+
[NODE_FIELD_REFERENCES]: referencedFields(settings),
|
|
511
536
|
};
|
|
512
537
|
}
|
|
513
538
|
|
|
514
539
|
export function quorum(
|
|
515
540
|
name: string,
|
|
516
541
|
settings: QuorumAuthoringSettings,
|
|
517
|
-
options: AuthoringIdOptions = {}
|
|
542
|
+
options: AuthoringIdOptions = {},
|
|
518
543
|
): AuthoredQuorumNode {
|
|
519
|
-
const id = options.id ?? mintedId(
|
|
544
|
+
const id = options.id ?? mintedId("quorum", name);
|
|
520
545
|
const { exam, ...settingsWithoutExam } = settings;
|
|
521
546
|
return {
|
|
522
547
|
id,
|
|
523
|
-
type:
|
|
548
|
+
type: "quorum",
|
|
524
549
|
settings: {
|
|
525
550
|
...settingsWithoutExam,
|
|
526
551
|
entities: {
|
|
527
552
|
input: settings.entities.input.map(compileGenerationInputEntity),
|
|
528
|
-
output: settings.entities.output.map(compileGenerationInputEntity)
|
|
553
|
+
output: settings.entities.output.map(compileGenerationInputEntity),
|
|
529
554
|
},
|
|
530
555
|
qualityCriteria: settings.qualityCriteria.map((criterion) => ({
|
|
531
556
|
...criterion,
|
|
532
|
-
targetEntity: criterion.targetEntity.id
|
|
557
|
+
targetEntity: criterion.targetEntity.id,
|
|
533
558
|
})),
|
|
534
559
|
...(exam === undefined
|
|
535
560
|
? {}
|
|
@@ -538,33 +563,36 @@ export function quorum(
|
|
|
538
563
|
...exam,
|
|
539
564
|
gradedEntities: exam.gradedEntities.map((entity) => ({
|
|
540
565
|
...entity,
|
|
541
|
-
targetEntity: entity.targetEntity.id
|
|
542
|
-
}))
|
|
543
|
-
}
|
|
544
|
-
})
|
|
566
|
+
targetEntity: entity.targetEntity.id,
|
|
567
|
+
})),
|
|
568
|
+
},
|
|
569
|
+
}),
|
|
545
570
|
},
|
|
546
|
-
input: inputPort(id,
|
|
547
|
-
output: outputPort(id,
|
|
548
|
-
[NODE_FIELD_REFERENCES]: referencedFields(settings)
|
|
571
|
+
input: inputPort(id, "input"),
|
|
572
|
+
output: outputPort(id, "output"),
|
|
573
|
+
[NODE_FIELD_REFERENCES]: referencedFields(settings),
|
|
549
574
|
};
|
|
550
575
|
}
|
|
551
576
|
|
|
552
577
|
export function connect(
|
|
553
578
|
from: OutputPort,
|
|
554
579
|
to: InputPort,
|
|
555
|
-
settings: PipelineGraphV1[
|
|
580
|
+
settings: PipelineGraphV1["connections"][number]["settings"] = {},
|
|
556
581
|
): Connection {
|
|
557
582
|
return { from, to, settings };
|
|
558
583
|
}
|
|
559
584
|
|
|
560
585
|
export function definePipeline<const DatasetName extends string>(
|
|
561
|
-
definition: PipelineDefinitionInput<DatasetName
|
|
586
|
+
definition: PipelineDefinitionInput<DatasetName>,
|
|
562
587
|
): PipelineDefinition<DatasetName> {
|
|
563
|
-
assert(definition.dataset.length > 0,
|
|
588
|
+
assert(definition.dataset.length > 0, "Dataset name must not be empty");
|
|
564
589
|
const declaredFields = new Set(definition.fields);
|
|
565
590
|
const declaredFieldIds = new Set<string>();
|
|
566
591
|
for (const declaredField of definition.fields) {
|
|
567
|
-
assert(
|
|
592
|
+
assert(
|
|
593
|
+
!declaredFieldIds.has(declaredField.id),
|
|
594
|
+
`Field id "${declaredField.id}" is declared more than once`,
|
|
595
|
+
);
|
|
568
596
|
declaredFieldIds.add(declaredField.id);
|
|
569
597
|
}
|
|
570
598
|
|
|
@@ -575,14 +603,20 @@ export function definePipeline<const DatasetName extends string>(
|
|
|
575
603
|
for (const referencedField of node[NODE_FIELD_REFERENCES]) {
|
|
576
604
|
assert(
|
|
577
605
|
declaredFields.has(referencedField),
|
|
578
|
-
`Field "${referencedField.name}" (${referencedField.id}) is referenced by node "${node.id}" but is not declared
|
|
606
|
+
`Field "${referencedField.name}" (${referencedField.id}) is referenced by node "${node.id}" but is not declared`,
|
|
579
607
|
);
|
|
580
608
|
}
|
|
581
609
|
}
|
|
582
610
|
|
|
583
611
|
for (const connection of definition.connections) {
|
|
584
|
-
assert(
|
|
585
|
-
|
|
612
|
+
assert(
|
|
613
|
+
declaredNodeIds.has(connection.from.node),
|
|
614
|
+
`Connection source node "${connection.from.node}" is not declared`,
|
|
615
|
+
);
|
|
616
|
+
assert(
|
|
617
|
+
declaredNodeIds.has(connection.to.node),
|
|
618
|
+
`Connection target node "${connection.to.node}" is not declared`,
|
|
619
|
+
);
|
|
586
620
|
}
|
|
587
621
|
|
|
588
622
|
return {
|
|
@@ -593,57 +627,68 @@ export function definePipeline<const DatasetName extends string>(
|
|
|
593
627
|
fields: definition.fields.map(({ id, name, jsonSchema }) => ({ id, name, jsonSchema })),
|
|
594
628
|
nodes: definition.nodes.map((node) => {
|
|
595
629
|
switch (node.type) {
|
|
596
|
-
case
|
|
630
|
+
case "root":
|
|
597
631
|
return { id: node.id, type: node.type, settings: node.settings };
|
|
598
|
-
case
|
|
632
|
+
case "code":
|
|
599
633
|
return { id: node.id, type: node.type, settings: node.settings };
|
|
600
|
-
case
|
|
634
|
+
case "generation":
|
|
601
635
|
return { id: node.id, type: node.type, settings: node.settings };
|
|
602
|
-
case
|
|
636
|
+
case "match":
|
|
603
637
|
return { id: node.id, type: node.type, settings: node.settings };
|
|
604
|
-
case
|
|
638
|
+
case "quorum":
|
|
605
639
|
return { id: node.id, type: node.type, settings: node.settings };
|
|
606
640
|
}
|
|
607
641
|
}),
|
|
608
642
|
connections: definition.connections.map(({ from, to, settings }) => ({
|
|
609
643
|
from: { node: from.node, handle: from.handle },
|
|
610
644
|
to: { node: to.node, handle: to.handle },
|
|
611
|
-
settings
|
|
612
|
-
}))
|
|
613
|
-
}
|
|
645
|
+
settings,
|
|
646
|
+
})),
|
|
647
|
+
},
|
|
614
648
|
};
|
|
615
649
|
}
|
|
616
650
|
|
|
617
651
|
export function isPipelineDefinition(value: unknown): value is PipelineDefinition {
|
|
618
|
-
return typeof value ===
|
|
652
|
+
return typeof value === "object" && value !== null && PIPELINE_DEFINITION in value;
|
|
619
653
|
}
|
|
620
654
|
|
|
621
655
|
export function validatePipelineDefinition(value: unknown): asserts value is PipelineDefinition {
|
|
622
|
-
assert(
|
|
623
|
-
|
|
656
|
+
assert(
|
|
657
|
+
isPipelineDefinition(value),
|
|
658
|
+
"Invalid pipeline definition: expected a value returned by definePipeline",
|
|
659
|
+
);
|
|
660
|
+
assert(value.dataset.length > 0, "Dataset name must not be empty");
|
|
624
661
|
for (const node of value.graph.nodes) {
|
|
625
|
-
if (node.type !==
|
|
626
|
-
assert(
|
|
627
|
-
|
|
662
|
+
if (node.type !== "root") continue;
|
|
663
|
+
assert(
|
|
664
|
+
!("datasetId" in node.settings),
|
|
665
|
+
"An unresolved pipeline definition cannot contain a dataset id",
|
|
666
|
+
);
|
|
667
|
+
assert(
|
|
668
|
+
!("itemFilter" in node.settings),
|
|
669
|
+
"An unresolved pipeline definition cannot contain a dataset item filter",
|
|
670
|
+
);
|
|
628
671
|
}
|
|
629
672
|
validate(value.graph);
|
|
630
673
|
}
|
|
631
674
|
|
|
632
675
|
export function resolvePipelineDefinition(
|
|
633
676
|
definition: PipelineDefinition,
|
|
634
|
-
bindings: PipelineDefinitionBindings
|
|
677
|
+
bindings: PipelineDefinitionBindings,
|
|
635
678
|
): PipelineGraphV1 {
|
|
636
679
|
const graph: PipelineGraphV1 = {
|
|
637
680
|
version: definition.graph.version,
|
|
638
681
|
fields: definition.graph.fields.map((fieldDefinition) => ({ ...fieldDefinition })),
|
|
639
682
|
nodes: definition.graph.nodes.map((node) =>
|
|
640
|
-
node.type ===
|
|
683
|
+
node.type === "root"
|
|
684
|
+
? { ...node, settings: { ...node.settings, datasetId: bindings.datasetId } }
|
|
685
|
+
: node,
|
|
641
686
|
),
|
|
642
687
|
connections: definition.graph.connections.map((connection) => ({
|
|
643
688
|
from: { ...connection.from },
|
|
644
689
|
to: { ...connection.to },
|
|
645
|
-
settings: { ...connection.settings }
|
|
646
|
-
}))
|
|
690
|
+
settings: { ...connection.settings },
|
|
691
|
+
})),
|
|
647
692
|
};
|
|
648
693
|
validate(graph);
|
|
649
694
|
return graph;
|