@toloka-platform/sdk 0.11.2 → 0.11.3
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/dist/cli/toloka.js +157 -154
- 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/authoring.md +6 -4
- package/docs/cli.md +30 -11
- package/docs/limitations.md +2 -2
- package/docs/testing.md +4 -2
- package/examples/README.md +11 -0
- package/examples/app-crowdtesting/README.md +41 -0
- package/examples/app-crowdtesting/fields.ts +6 -0
- package/examples/app-crowdtesting/nodes/app-flow-test/node.ts +381 -0
- package/examples/app-crowdtesting/nodes/collection/node.ts +8 -0
- package/examples/app-crowdtesting/pipeline.browser.integration.spec.ts +77 -0
- package/examples/app-crowdtesting/pipeline.ts +17 -0
- package/examples/egocentric-video-collection/README.md +35 -0
- package/examples/egocentric-video-collection/fields.ts +24 -0
- package/examples/egocentric-video-collection/nodes/collection/node.ts +5 -0
- package/examples/egocentric-video-collection/nodes/record-activity/node.ts +760 -0
- package/examples/egocentric-video-collection/pipeline.browser.integration.spec.ts +65 -0
- package/examples/egocentric-video-collection/pipeline.ts +17 -0
- package/examples/product-moderation/README.md +49 -0
- package/examples/product-moderation/fields.ts +37 -0
- package/examples/product-moderation/nodes/collection/node.ts +16 -0
- package/examples/product-moderation/nodes/moderate-product/instruction.ts +77 -0
- package/examples/product-moderation/nodes/moderate-product/node.ts +368 -0
- package/examples/product-moderation/pipeline.browser.integration.spec.ts +48 -0
- package/examples/product-moderation/pipeline.ts +33 -0
- package/examples/video-pair-rating/fields.ts +16 -4
- package/examples/video-pair-rating/nodes/adjudicate/node.ts +78 -3
- package/examples/video-pair-rating/nodes/adjudicate_op/node.ts +28 -3
- package/examples/video-pair-rating/nodes/overall_preference_pick/node.ts +28 -3
- package/examples/video-pair-rating/nodes/rate_pair/node.ts +65 -2
- package/openapi/gen/api.ts +22 -0
- package/openapi/gen/models/generationBudget.ts +8 -0
- package/openapi/gen/models/generationBudgetReasoningEffort.ts +2 -0
- package/openapi/gen/models/generationModel.ts +12 -0
- package/openapi/gen/models/generationModelDefaultReasoningEffort.ts +2 -0
- package/openapi/gen/models/generationModelId.ts +2 -0
- package/openapi/gen/models/index.ts +8 -0
- package/openapi/gen/models/invalidFieldSchema.ts +6 -0
- package/openapi/gen/models/listGenerationModels200.ts +7 -0
- package/openapi/gen/models/listGenerationModels200DefaultGenerationModelId.ts +2 -0
- package/openapi/gen/models/pipelineGraphSnapshot.ts +2 -0
- package/package.json +2 -2
- package/skills/catalog.json +16 -12
- package/skills/toloka-build/SKILL.md +44 -58
- package/skills/toloka-build/references/human-work.md +156 -0
- package/skills/toloka-build/references/local-setup.md +136 -0
- package/skills/toloka-build/references/node-checks.md +11 -0
- package/skills/toloka-build/references/node-semantics.md +22 -213
- package/skills/toloka-build/references/task-ui.md +61 -0
- package/skills/toloka-build/references/workflow-and-cli.md +29 -229
- package/skills/toloka-fine-tuning/SKILL.md +1 -1
- package/skills/toloka-get-started/SKILL.md +1 -1
- package/skills/toloka-gisting/SKILL.md +1 -1
- package/src/authoring/index.ts +26 -7
- package/src/checks/task-ui-typecheck.ts +3 -3
- package/src/cli/analytics.ts +1 -0
- package/src/cli/check.ts +83 -12
- package/src/cli/commands/generation-model.ts +18 -0
- package/src/cli/commands/pipeline.ts +1 -1
- package/src/cli/commands/source.ts +14 -3
- package/src/cli/generation-models.ts +46 -0
- package/src/cli/program.ts +2 -0
- package/src/cli/project.ts +288 -138
- package/src/cli/trainings.ts +12 -0
- package/src/cli/ui.ts +3 -1
- package/src/client.ts +5 -0
- package/src/graph-rules.json +11 -0
- package/src/importer.ts +46 -40
- package/src/index.ts +4 -0
- package/src/validate.ts +183 -0
package/dist/cli/toloka.js.jsc
CHANGED
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
6f99f48f6bd7c933cd5d2f6b2382d9c4149e6cfb4a39a32364d49994a16f436e toloka.js.jsc
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
a038b95e14fe030c3d9b59182799dc89f8c76fd501fe42036831ea3d1daa27c5 toloka.js
|
package/docs/authoring.md
CHANGED
|
@@ -225,7 +225,7 @@ A quorum node **requires** an `onboarding` block: the Training course is part of
|
|
|
225
225
|
|
|
226
226
|
### match
|
|
227
227
|
|
|
228
|
-
Predicate routing. Conditions are evaluated in declaration order.
|
|
228
|
+
Predicate routing. Conditions are evaluated in declaration order. A condition's `logic` defaults to `'and'`, so every predicate must match; set `logic: 'or'` when any one predicate should match. `match()` writes the default into the graph, as the platform stores it, so `toloka plan` does not report the condition as changed after an apply.
|
|
229
229
|
|
|
230
230
|
```ts
|
|
231
231
|
import { match } from "@toloka-platform/sdk";
|
|
@@ -284,7 +284,9 @@ export default definePipeline({
|
|
|
284
284
|
});
|
|
285
285
|
```
|
|
286
286
|
|
|
287
|
-
`dataset` names the source dataset. `
|
|
287
|
+
`dataset` names the source dataset. `apply` creates it if it is absent, binds it to the pipeline, and records the resolved id in `toloka.json`.
|
|
288
|
+
|
|
289
|
+
Leave `dataset` out for a pipeline that has no dataset yet, such as one created from a template in the platform UI. `plan` and `apply` then edit its graph without binding a dataset, and `toloka import` writes such a pipeline the same way. The pipeline cannot run until it has a dataset: add `dataset` to its source later, or bind one in the platform UI and import again. Apply never removes a bound dataset, so it refuses to apply a source that drops `dataset` from a pipeline that has one.
|
|
288
290
|
|
|
289
291
|
Each `pipelines/<name>/pipeline.ts` is one pipeline. A project can hold several; each names its own dataset, and a dataset can be shared.
|
|
290
292
|
|
|
@@ -296,7 +298,7 @@ Constructors mint deterministic ids from the node name, so authored source needs
|
|
|
296
298
|
|
|
297
299
|
`toloka import` emits explicit `{ id }` options for nodes and fields that already exist on the platform. **Preserve them.** They are how reconciliation recognizes the same resource instead of replacing it.
|
|
298
300
|
|
|
299
|
-
Never hand-write `fp_…`, `ds.…`, `pl.…`, or `pp.…` values into settings, and never author a `layout` block: layout is not authored, existing
|
|
301
|
+
Never hand-write `fp_…`, `ds.…`, `pl.…`, or `pp.…` values into settings, and never author a `layout` block: layout is not authored, existing nodes keep their canvas position, and the server places new nodes one column after their rightmost input and moves End to the right when they reach it.
|
|
300
302
|
|
|
301
303
|
## Validate
|
|
302
304
|
|
|
@@ -305,7 +307,7 @@ toloka check
|
|
|
305
307
|
toloka validate
|
|
306
308
|
```
|
|
307
309
|
|
|
308
|
-
`definePipeline` and the typed ports add local declaration and connection invariants. `toloka validate` posts each bound pipeline to `POST /pipelines/:pipelineId/graph/validate` and reports platform spec errors, warnings, and the latest matching check jobs. It does not write the graph.
|
|
310
|
+
`definePipeline` and the typed ports add local declaration and connection invariants. `toloka check` also reports, as warnings, the platform rules that would reject a node connected to the root: node names, unique quality elements, quality-criterion thresholds, the minimum task and Human QA review times, a positive price per task, a media upload component on a human `data_collection` node, and the limits of an enabled exam. `toloka apply` refuses to write a new or changed pipeline that breaks them, before any platform write; an unchanged pipeline, such as a draft saved in the platform UI, does not block apply of the others. `toloka validate` posts each bound pipeline to `POST /pipelines/:pipelineId/graph/validate` and reports platform spec errors, warnings, and the latest matching check jobs. It does not write the graph.
|
|
309
311
|
|
|
310
312
|
A pipeline that is not on the platform yet is skipped until `toloka apply` creates it. The published JSON contract is still available as `validate(graph)` for importer and fixture tests; that helper also runs the local entity checks described under [generation](#generation) and makes no network call.
|
|
311
313
|
|
package/docs/cli.md
CHANGED
|
@@ -178,6 +178,16 @@ toloka audience specialization list [--json]
|
|
|
178
178
|
|
|
179
179
|
Lists every expert specialization (platform qualification) with `ID`, `NAME`, and `EXPERTS` columns, sorted by name. Copy `ID` into `qualificationId` and `NAME` into `value` of `audience.specializations.values[]`; never invent a `qualificationId`. `EXPERTS` is the number of ID-verified experts currently eligible for tasks who hold the specialization; it can be `0` while the id is still valid. Pass `--json` for the full array. Empty output is `No specializations available.`
|
|
180
180
|
|
|
181
|
+
## generation-model
|
|
182
|
+
|
|
183
|
+
Inspect the global, read-only catalog of models a synthetic `generation` node can use.
|
|
184
|
+
|
|
185
|
+
```sh
|
|
186
|
+
toloka generation-model list [--json]
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Prints one row per model and reasoning effort with `ID`, `NAME`, `REASONING EFFORT`, `TYPICAL`, `MIN`, and `MAX` columns, then the default and recommended models. Copy `ID` into `generationModelId`. A `-` in `REASONING EFFORT` means the model does not support `reasoningEffort`; leave it unset there. `MIN` and `MAX` bound the `maxCostPerAttempt` apply accepts; a budget below `TYPICAL` is accepted with a warning because generation can stop before the result is complete. `--json` adds each model's description. Empty output is `No generation models available.`
|
|
190
|
+
|
|
181
191
|
## login
|
|
182
192
|
|
|
183
193
|
Signs in through the browser, or stores an API key, after verifying access.
|
|
@@ -250,27 +260,33 @@ Generates TypeScript source from a live project.
|
|
|
250
260
|
toloka import [projectId] [-f]
|
|
251
261
|
```
|
|
252
262
|
|
|
253
|
-
When `projectId` is omitted, the selected project is imported. If `pipelines/` already exists, the command exits with `Folder already exists: <path>. Pass --force to replace it.` Pass `-f` or `--force` to replace that directory. On success it prints `Imported project <projectId> with N pipelines and M datasets into <root>.`
|
|
263
|
+
When `projectId` is omitted, the selected project is imported. If `pipelines/` already exists, the command exits with `Folder already exists: <path>. Pass --force to replace it.` Pass `-f` or `--force` to replace that directory. On success it prints `Imported project <projectId> with N pipelines and M datasets into <root>.` A pipeline without a dataset is written without `dataset` in its `definePipeline`.
|
|
264
|
+
|
|
265
|
+
The generated nodes keep every stored check case, including cases of the retired `ui` and `llmqa` types. A check type with no cases is left out, and a node whose check types are all empty gets no `checks` at all. `plan` and `apply` treat a check type that source leaves out as unmanaged: they neither report nor remove the cases the platform has for it, so set a type to an empty array to remove its cases.
|
|
266
|
+
|
|
267
|
+
A field whose JSON Schema is stored on the platform as invalid JSON or as an unsupported schema, for example after an unfinished edit in the UI, is imported as `field("name", invalidJsonSchema({ field, reason, text }))` with the stored text. Loading the source then fails with `Field "<name>" has an unreadable JSON Schema on the platform.` until you replace the call with a valid JSON Schema object; the next `apply` writes that schema and repairs the field.
|
|
254
268
|
|
|
255
269
|
## plan
|
|
256
270
|
|
|
257
271
|
Shows what `apply` would change.
|
|
258
272
|
|
|
259
273
|
```sh
|
|
260
|
-
toloka plan
|
|
274
|
+
toloka plan [--json]
|
|
261
275
|
```
|
|
262
276
|
|
|
263
|
-
On success it prints `No changes.` when the platform matches source, otherwise `Plan: N changes` followed by one line per change. The plan also lists missing project secrets and dataset field schema conflicts so you can resolve them before applying.
|
|
277
|
+
On success it prints `No changes.` when the platform matches source, otherwise `Plan: N changes` followed by one line per change. The plan also lists missing project secrets and dataset field schema conflicts so you can resolve them before applying. `--json` prints `{ "changes": [...], "missingSecrets": [...] }` instead, where each change has `kind`, `action`, `label`, and, when they apply, `pipeline`, `dataset`, and `id`.
|
|
264
278
|
|
|
265
279
|
## validate
|
|
266
280
|
|
|
267
281
|
Runs platform spec validation for each bound pipeline and reports the latest matching check jobs. Does not write the graph.
|
|
268
282
|
|
|
269
283
|
```sh
|
|
270
|
-
toloka validate
|
|
284
|
+
toloka validate [--wait]
|
|
271
285
|
```
|
|
272
286
|
|
|
273
|
-
|
|
287
|
+
It prints one line per pipeline with its status, then its issues: `valid`; `invalid`; `checks-pending` when only check state is open, such as a stored test case or a lint that has not run on this graph; `checks-running` when `--wait` gave up on running checks; or `skipped` when the pipeline or its dataset is not on the platform yet. A `note:` line explains what to do next when `--wait` could not finish. Exits `1` when any submitted graph is invalid or its checks were still running at the `--wait` deadline.
|
|
288
|
+
|
|
289
|
+
The platform lints a pipeline a few seconds after every apply. While a lint or a check is running, or a lint is about to start after an apply, validate lists it as `running running_node_check`; a lint that has not run on this graph and is no longer expected to start is `pending not_ran_node_check`, and the user runs it from the node's Checks tab. `--wait` validates again every 5 seconds until nothing is running, for up to 5 minutes, then prints the final report; a pipeline whose source differs from the applied graph is not waited on, because its lints start only after `toloka apply`. Right after an apply, plain `toloka validate` can print `valid` and exit `0` while lints are still running, so run `toloka validate --wait` before treating an applied pipeline as valid.
|
|
274
290
|
|
|
275
291
|
## check
|
|
276
292
|
|
|
@@ -280,7 +296,7 @@ Runs the complete local gate without platform credentials.
|
|
|
280
296
|
toloka check [pipeline] [--node <name-or-id>] [--json] [--watch]
|
|
281
297
|
```
|
|
282
298
|
|
|
283
|
-
The command loads authored source, runs the project's TypeScript compiler, typechecks every Task UI against declarations bundled with the installed SDK, runs Vitest, and compares passing typed test evidence with every code node, human-work node, and pipeline. Statuses distinguish `missing`, `failed`, `partial`, and `infrastructure_error`. Exit code `0` means all required checks passed, `1` means source, types, tests, or required coverage failed, and `2` means a required checker could not run.
|
|
299
|
+
The command loads authored source, runs the project's TypeScript compiler, typechecks every Task UI against declarations bundled with the installed SDK, runs Vitest, and compares passing typed test evidence with every code node, human-work node, and pipeline. Statuses distinguish `missing`, `failed`, `partial`, `warning`, and `infrastructure_error`. `partial` marks a Task UI whose upload or recording fields the headless browser could not exercise; it is reported but does not fail the gate. `warning` marks a `platform-rules` result: nodes connected to the root that break a rule the platform enforces on write. It does not fail the gate, but `toloka apply` refuses to write that pipeline until it is fixed. Exit code `0` means all required checks passed, `1` means source, types, tests, or required coverage failed, and `2` means a required checker could not run.
|
|
284
300
|
|
|
285
301
|
Use `test.code`, `test.ui`, and `test.pipeline` from `@toloka-platform/sdk/testing` to produce required evidence. Plain Vitest tests still run and can fail the command, but do not satisfy graph coverage. A focused check accepts a pipeline plus `--node`; `--watch` serializes reruns after relevant file changes.
|
|
286
302
|
|
|
@@ -288,7 +304,7 @@ With `--watch`, the command prints one complete report after each serialized run
|
|
|
288
304
|
|
|
289
305
|
## apply
|
|
290
306
|
|
|
291
|
-
Runs the complete
|
|
307
|
+
Runs the complete local gate, then makes the platform match source. It takes no options and never asks for confirmation.
|
|
292
308
|
|
|
293
309
|
```sh
|
|
294
310
|
toloka apply
|
|
@@ -426,7 +442,7 @@ Inspect the Task UI components the launcher renders. The command opens the launc
|
|
|
426
442
|
toloka ui components [names...] [--json]
|
|
427
443
|
```
|
|
428
444
|
|
|
429
|
-
Without names it prints one line per public component (`name: description
|
|
445
|
+
Without names it prints one line per public component (`name: description When to use: …`). With names it prints each component's description, when to use it, capabilities, limitations, best practices, the `propsType` contract, the value shape, and the documented JSX example with its output. An unknown name fails with `Unknown Task UI components: <name>`. `--json` prints the same contracts keyed by component name. The output always reflects the currently deployed launcher, so run it instead of guessing component names or props from memory.
|
|
430
446
|
|
|
431
447
|
## skill
|
|
432
448
|
|
|
@@ -464,7 +480,7 @@ An unknown command exits 1 before anything else runs, even when `--help` is pres
|
|
|
464
480
|
|
|
465
481
|
## The reconcile loop
|
|
466
482
|
|
|
467
|
-
Treat the TypeScript source as authoritative. The canonical sequence is: run the complete local gate, validate against the platform, plan, apply, then plan again to confirm convergence.
|
|
483
|
+
Treat the TypeScript source as authoritative. The canonical sequence is: run the complete local gate, validate against the platform, plan, apply, validate again once the platform lints finish, then plan again to confirm convergence.
|
|
468
484
|
|
|
469
485
|
```sh
|
|
470
486
|
# 1. Run source, type, and typed test checks
|
|
@@ -479,11 +495,14 @@ toloka plan
|
|
|
479
495
|
# 4. Apply only when the plan matches the intent
|
|
480
496
|
toloka apply
|
|
481
497
|
|
|
482
|
-
# 5.
|
|
498
|
+
# 5. Wait for the platform lints that start after apply
|
|
499
|
+
toloka validate --wait
|
|
500
|
+
|
|
501
|
+
# 6. Confirm the platform matches source
|
|
483
502
|
toloka plan # expect: No changes.
|
|
484
503
|
```
|
|
485
504
|
|
|
486
|
-
`toloka apply` reruns the complete local gate before resolving credentials. `toloka validate` posts each authored graph to `POST /pipelines/:pipelineId/graph/validate`; it reports platform spec validation and the latest matching
|
|
505
|
+
`toloka apply` reruns the complete local gate before resolving credentials. `toloka validate` posts each authored graph to `POST /pipelines/:pipelineId/graph/validate`; it reports platform spec validation and the latest matching check runs without writing the graph. Resolve every unexpected plan change, missing secret, and immutable-field conflict before applying.
|
|
487
506
|
|
|
488
507
|
## Further reading
|
|
489
508
|
|
package/docs/limitations.md
CHANGED
|
@@ -19,7 +19,7 @@ The standalone CLI supports macOS and glibc Linux on ARM64 and x64. Native Windo
|
|
|
19
19
|
| Training course content, when Training is enabled | platform validation | nothing |
|
|
20
20
|
| labeler UI validation receipt | platform validation | nothing |
|
|
21
21
|
|
|
22
|
-
The typed client can list, start, and poll Remote Node Checks. `toloka check` does not start them: it validates the authored source and its local tests. A `not_ran_node_check`
|
|
22
|
+
The typed client can list, start, and poll Remote Node Checks. `toloka check` does not start them: it validates the authored source and its local tests. A `not_ran_node_check` or `running_node_check` warning from `toloka validate` describes remote state rather than missing local evidence.
|
|
23
23
|
|
|
24
24
|
Python code nodes have executable behavior checks but no useful static Python typecheck yet. Their generated `Inputs` and `Outputs` aliases are currently `dict[str, Any]`; adding Pyright or mypy before those aliases become field-derived `TypedDict` contracts would provide little protection.
|
|
25
25
|
|
|
@@ -27,7 +27,7 @@ The standalone CLI's runtime does not provide project test dependencies. Executa
|
|
|
27
27
|
|
|
28
28
|
## Layout is not authored
|
|
29
29
|
|
|
30
|
-
Node canvas positions are not part of authored source. Existing
|
|
30
|
+
Node canvas positions are not part of authored source. Existing nodes keep their canvas position across applies. The server places a new node one column to the right of its rightmost input, below any node already in that spot, and moves End to the right when new nodes reach it. You cannot lay out a graph from code.
|
|
31
31
|
|
|
32
32
|
## One checkout targets one project
|
|
33
33
|
|
package/docs/testing.md
CHANGED
|
@@ -17,7 +17,7 @@ bun add -d vitest playwright
|
|
|
17
17
|
bunx playwright install chromium
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
Executable code-node tests also require `python3` on the test machine
|
|
20
|
+
Executable code-node tests also require `python3` on the test machine. The platform runs code nodes on Python 3.12 with the standard library only, so a program that imports a package installed only on the test machine passes locally and fails on the platform. Browser-backed Task UI tests use the separately downloaded Playwright Chromium binary and require network access to the hosted launcher. Training-only CLI workflows require none of these project test tools or a separate JavaScript runtime. See [testing examples](./testing-examples.md) for parameterization, validation failures, hardware coverage, and cleanup patterns.
|
|
21
21
|
|
|
22
22
|
## Test a code node
|
|
23
23
|
|
|
@@ -110,6 +110,8 @@ Valid JavaScript: `items.map((item) => item.value)`
|
|
|
110
110
|
|
|
111
111
|
Invalid runtime JavaScript: `items.map((item: unknown) => item.value)`
|
|
112
112
|
|
|
113
|
+
Only `data` is in scope in `preprocess` and `postprocess`. `CONST` exists only in `ui.code`, so `toloka check` reports `Cannot find name 'CONST'` when either function reads it: write the value inline in the function, or read it from `ui.code` instead.
|
|
114
|
+
|
|
113
115
|
`preprocess` can run again after form state changes. Use it to shape input data; if it prefills a bound field, return that key only while it is absent so later edits are not overwritten. A `Field`-bound top-level key already enters the submission. `postprocess` must return only new top-level keys: bind a component to a draft key when postprocess must derive a different entity key.
|
|
114
116
|
|
|
115
117
|
The fixture loads the hosted TBX launcher in a fresh local Chromium context, so tests require network access but do not use Azure Playwright or Potato application services. The context has no platform cookies or credentials. Use synthetic or redacted fixtures because the hosted launcher executes with access to the supplied test data.
|
|
@@ -120,4 +122,4 @@ File pickers, video upload/recording, and other hardware-backed fields cannot be
|
|
|
120
122
|
|
|
121
123
|
## Final gate
|
|
122
124
|
|
|
123
|
-
`toloka check` loads every authored pipeline, runs the project TypeScript compiler, typechecks every Task UI against declarations bundled with the installed SDK, runs Vitest, and requires passing `test.code`, `test.ui`, and `test.pipeline` evidence. `missing`, `failed`,
|
|
125
|
+
`toloka check` loads every authored pipeline, runs the project TypeScript compiler, typechecks every Task UI against declarations bundled with the installed SDK, runs Vitest, and requires passing `test.code`, `test.ui`, and `test.pipeline` evidence. `missing`, `failed`, and `infrastructure_error` are distinct blocking outcomes. `partial` is reported for a Task UI with hardware-backed fields and does not block: verify those fields on a real device before launching a run. `toloka apply` reruns this complete gate before resolving credentials or writing platform state. Platform validation remains separate: a `not_ran_node_check` warning describes Remote Node Check state rather than missing local evidence.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
Complete pipeline projects to borrow structure from. Each directory has a README and a `pipeline.browser.integration.spec.ts` with its typed tests. Borrow the patterns, not the task-specific choices: design the graph, entities, criteria, and Task UI for the task at hand.
|
|
4
|
+
|
|
5
|
+
| example | read it for |
|
|
6
|
+
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| `product-moderation` | **start here for a show-an-item, collect-a-judgment task**: one human `generation` node that shows an image and text and collects a label, a subcategory, and a rationale; label lists shared by fields and UI; variants for synthetic generation and several experts |
|
|
8
|
+
| `face-image-collection` | a human image-annotation node followed by a code node; a structured array output |
|
|
9
|
+
| `video-pair-rating` | side-by-side rating with a `quorum`, deterministic code cascades over rater arrays, `match` routing with `default` branches, and human adjudication |
|
|
10
|
+
| `egocentric-video-collection` | data collection with a recording field, a category label driven by one constant list, LLM QA with one criterion per concern, Training with quizzes, stored checks |
|
|
11
|
+
| `app-crowdtesting` | data collection with an upload field plus structured metadata answers, a step-by-step screen with long text in `ui.constants`, contributor diversity via the per-expert cap |
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# App crowdtesting
|
|
2
|
+
|
|
3
|
+
A crowdtesting data-collection pipeline: each tester installs a pre-release Android build on their own phone, screen-records a full session through the app's key flows, uploads the recording, and reports their device model and Android version. An LLM reviews every submission against quality criteria before it is accepted.
|
|
4
|
+
|
|
5
|
+
The task content is built around a fictional app, Acme Fitness. To adopt it, replace the app everywhere it appears: the install link, node description and public name, entity descriptions, every quality criterion, the instruction, the Task UI constants, and the Training steps and quiz.
|
|
6
|
+
|
|
7
|
+
## Shape
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
root.started (item_id)
|
|
11
|
+
└─> app_flow_test generation a tester installs, records, uploads, and describes the device
|
|
12
|
+
└─> root.completed (app_test_video, device_model, os_version)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Two nodes: one root and one `data_collection` `generation`. Each dataset row is one recording slot; `item_id` carries no task content, so the number of rows is the number of recordings.
|
|
16
|
+
|
|
17
|
+
## What to read first
|
|
18
|
+
|
|
19
|
+
| file | why |
|
|
20
|
+
| -------------------------------------- | ------------------------------------------------------------------------- |
|
|
21
|
+
| `nodes/app-flow-test/node.ts` | the whole task: entities, criteria, instruction, Task UI, and Training |
|
|
22
|
+
| `fields.ts` | a scalar video field fed from a single upload, plus two free-text answers |
|
|
23
|
+
| `pipeline.browser.integration.spec.ts` | how to drive an upload component in a headless UI scenario |
|
|
24
|
+
|
|
25
|
+
## Patterns this example demonstrates
|
|
26
|
+
|
|
27
|
+
**One upload is one entity.** `Field.VideoUpload` always produces an array, but a tester submits one recording. The output field is a scalar URI, the entity is static, and its `jsonPath` selects `$.app_test_video[0].sasLink`, matching the component's `linkType={'sasLink'}` (the contract's recommended link type; `downloadLink` may be inaccessible to end users). Duration bounds are set on both the entity and the component, and they agree.
|
|
28
|
+
|
|
29
|
+
**Structured metadata next to the upload.** Device model and OS version are separate `SHORT_ANSWER` outputs related to the recording, each with a `required` rule and its own `max` length rule, and each with a criterion that rejects placeholders.
|
|
30
|
+
|
|
31
|
+
**A step-by-step screen.** The Task UI stacks install, record, and upload as three cards in the order the tester works. Long markdown and the install link live in `ui.constants` and are read as `CONST.*`, so `ui.code` needs no nested template literals and the install link is declared once for both the instruction and the screen.
|
|
32
|
+
|
|
33
|
+
**LLM QA judges what is visible.** Criteria count attempted flow runs and required screens by on-screen text, never by which control was tapped, and a captured crash counts as a completed run rather than a failure.
|
|
34
|
+
|
|
35
|
+
**Training that matches the task.** Three steps, ending in a quiz on the rules that most often fail a recording: when to start recording, how many runs each flow needs, and what to do when the app crashes.
|
|
36
|
+
|
|
37
|
+
**Contributor diversity.** An unverified English-speaking crowd with a per-expert cap of 1, so every recording comes from a different person and device.
|
|
38
|
+
|
|
39
|
+
## Check locally
|
|
40
|
+
|
|
41
|
+
Upload and recording controls are hardware-backed, and headless Chromium cannot pick, capture, or upload a file. The UI scenario renders with `allowPartialCoverage: true`, sets the upload value from the component's documented example output, and asserts that coverage is incomplete. It verifies browser validation and the output mapping, not the upload itself, so `toloka check` reports this node as `partial`.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { field } from "@toloka-platform/sdk";
|
|
2
|
+
|
|
3
|
+
export const itemId = field("item_id", { type: "number" });
|
|
4
|
+
export const appTestVideo = field("app_test_video", { type: "string", format: "uri" });
|
|
5
|
+
export const deviceModel = field("device_model", { type: "string" });
|
|
6
|
+
export const osVersion = field("os_version", { type: "string" });
|