@toloka-platform/sdk 0.11.2 → 0.11.4

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.
Files changed (76) hide show
  1. package/dist/cli/toloka.js +158 -154
  2. package/dist/cli/toloka.js.jsc +0 -0
  3. package/dist/cli/toloka.js.jsc.sha256 +1 -1
  4. package/dist/cli/toloka.js.sha256 +1 -1
  5. package/docs/authoring.md +6 -4
  6. package/docs/cli.md +30 -11
  7. package/docs/limitations.md +2 -2
  8. package/docs/testing.md +4 -2
  9. package/examples/README.md +11 -0
  10. package/examples/app-crowdtesting/README.md +41 -0
  11. package/examples/app-crowdtesting/fields.ts +6 -0
  12. package/examples/app-crowdtesting/nodes/app-flow-test/node.ts +381 -0
  13. package/examples/app-crowdtesting/nodes/collection/node.ts +8 -0
  14. package/examples/app-crowdtesting/pipeline.browser.integration.spec.ts +77 -0
  15. package/examples/app-crowdtesting/pipeline.ts +17 -0
  16. package/examples/egocentric-video-collection/README.md +35 -0
  17. package/examples/egocentric-video-collection/fields.ts +24 -0
  18. package/examples/egocentric-video-collection/nodes/collection/node.ts +5 -0
  19. package/examples/egocentric-video-collection/nodes/record-activity/node.ts +760 -0
  20. package/examples/egocentric-video-collection/pipeline.browser.integration.spec.ts +65 -0
  21. package/examples/egocentric-video-collection/pipeline.ts +17 -0
  22. package/examples/product-moderation/README.md +49 -0
  23. package/examples/product-moderation/fields.ts +37 -0
  24. package/examples/product-moderation/nodes/collection/node.ts +16 -0
  25. package/examples/product-moderation/nodes/moderate-product/instruction.ts +77 -0
  26. package/examples/product-moderation/nodes/moderate-product/node.ts +368 -0
  27. package/examples/product-moderation/pipeline.browser.integration.spec.ts +48 -0
  28. package/examples/product-moderation/pipeline.ts +33 -0
  29. package/examples/video-pair-rating/fields.ts +16 -4
  30. package/examples/video-pair-rating/nodes/adjudicate/node.ts +78 -3
  31. package/examples/video-pair-rating/nodes/adjudicate_op/node.ts +28 -3
  32. package/examples/video-pair-rating/nodes/overall_preference_pick/node.ts +28 -3
  33. package/examples/video-pair-rating/nodes/rate_pair/node.ts +65 -2
  34. package/openapi/gen/api.ts +22 -0
  35. package/openapi/gen/models/generationBudget.ts +8 -0
  36. package/openapi/gen/models/generationBudgetReasoningEffort.ts +2 -0
  37. package/openapi/gen/models/generationModel.ts +12 -0
  38. package/openapi/gen/models/generationModelDefaultReasoningEffort.ts +2 -0
  39. package/openapi/gen/models/generationModelId.ts +2 -0
  40. package/openapi/gen/models/index.ts +8 -0
  41. package/openapi/gen/models/invalidFieldSchema.ts +6 -0
  42. package/openapi/gen/models/listGenerationModels200.ts +7 -0
  43. package/openapi/gen/models/listGenerationModels200DefaultGenerationModelId.ts +2 -0
  44. package/openapi/gen/models/pipelineGraphSnapshot.ts +2 -0
  45. package/package.json +2 -2
  46. package/skills/catalog.json +16 -12
  47. package/skills/toloka-build/SKILL.md +44 -58
  48. package/skills/toloka-build/references/human-work.md +156 -0
  49. package/skills/toloka-build/references/local-setup.md +136 -0
  50. package/skills/toloka-build/references/node-checks.md +11 -0
  51. package/skills/toloka-build/references/node-semantics.md +22 -213
  52. package/skills/toloka-build/references/task-ui.md +61 -0
  53. package/skills/toloka-build/references/workflow-and-cli.md +34 -228
  54. package/skills/toloka-fine-tuning/SKILL.md +1 -1
  55. package/skills/toloka-get-started/SKILL.md +1 -1
  56. package/skills/toloka-gisting/SKILL.md +1 -1
  57. package/src/authoring/index.ts +26 -7
  58. package/src/checks/task-ui-typecheck.ts +3 -3
  59. package/src/cli/analytics.ts +1 -0
  60. package/src/cli/check.ts +83 -12
  61. package/src/cli/commands/generation-model.ts +18 -0
  62. package/src/cli/commands/pipeline.ts +1 -1
  63. package/src/cli/commands/source.ts +14 -3
  64. package/src/cli/data.ts +5 -2
  65. package/src/cli/format-error.ts +3 -0
  66. package/src/cli/generation-models.ts +46 -0
  67. package/src/cli/program.ts +2 -0
  68. package/src/cli/project.ts +288 -138
  69. package/src/cli/trainings.ts +12 -0
  70. package/src/cli/ui.ts +3 -1
  71. package/src/client.ts +5 -0
  72. package/src/graph-rules.json +11 -0
  73. package/src/importer.ts +46 -40
  74. package/src/index.ts +4 -0
  75. package/src/transport.ts +23 -5
  76. package/src/validate.ts +183 -0
Binary file
@@ -1 +1 @@
1
- 1024b0621937fe114806d81e918925d05e4e71ef8c2f6aa209eabbe9aa102e02 toloka.js.jsc
1
+ a7b5f9f339e9293bf388a7a57c15cfa4297942cdb7243e8b53d116661ddf5f0d toloka.js.jsc
@@ -1 +1 @@
1
- 2e9290a8e04d18db2dd275be6fc273d15459a67f6b1f98d27aebf1c6bdfd7fa1 toloka.js
1
+ 3c36c2751f8365c8ed466bd389723fa1d836d2ec5e61850450e4a725648ec0f8 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. `plan` creates it if it is absent and records the resolved id in `toloka.json`.
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 layout is preserved, and the server supplies defaults.
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
- On success it prints one line per pipeline: `valid`, `invalid` with issue details, or `skipped` when the pipeline is not on the platform yet. Exits `1` when any submitted graph is invalid.
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 Local Check Gate, then makes the platform match source.
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`). 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.
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. Confirm the platform matches source
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 Remote Node Check jobs without writing the graph. Resolve every unexpected plan change, missing secret, and immutable-field conflict before applying.
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
 
@@ -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` result from `toloka validate` describes remote state rather than missing local evidence. Its severity is check-specific: lint checks report a blocking error, while other checks can report a warning.
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 layout is preserved across applies and the server supplies defaults for new nodes. You cannot lay out a graph from code.
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, including any third-party Python packages imported by the authored program. 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.
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`, `partial`, and `infrastructure_error` are distinct blocking outcomes. `toloka apply` reruns this complete gate before resolving credentials or writing platform state. Platform validation remains separate: a `not_ran_node_check` describes Remote Node Check state rather than missing local evidence, but lint checks report it as a blocking remote error while other checks can report it as a warning.
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" });