@toloka-platform/sdk 0.1.0-preview.4 → 0.1.0-preview.6

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 (60) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/toloka.js +132 -126
  3. package/dist/cli/toloka.js.jsc +0 -0
  4. package/dist/cli/toloka.js.jsc.sha256 +1 -1
  5. package/dist/cli/toloka.js.sha256 +1 -1
  6. package/docs/cli-v2.md +4 -0
  7. package/docs/cli.md +82 -6
  8. package/docs/datasets.md +8 -9
  9. package/docs/getting-started.md +2 -2
  10. package/docs/limitations.md +5 -8
  11. package/docs/troubleshooting.md +0 -11
  12. package/openapi/gen/api.ts +782 -876
  13. package/openapi/gen/models/baseModel.ts +9 -0
  14. package/openapi/gen/models/baseModelId.ts +2 -0
  15. package/openapi/gen/models/baseModelIdProperty.ts +2 -0
  16. package/openapi/gen/models/createDatasetBody.ts +2 -0
  17. package/openapi/gen/models/createDatasetBodyProfile.ts +2 -0
  18. package/openapi/gen/models/createDatasetUploadBodyFormat.ts +1 -1
  19. package/openapi/gen/models/createProjectModelBody.ts +8 -0
  20. package/openapi/gen/models/createProjectModelBodyDescription.ts +2 -0
  21. package/openapi/gen/models/dataset.ts +2 -0
  22. package/openapi/gen/models/datasetProfile.ts +3 -0
  23. package/openapi/gen/models/datasetProfileStamp.ts +6 -0
  24. package/openapi/gen/models/datasetProfileStampName.ts +2 -0
  25. package/openapi/gen/models/generationNodeSettingsAudienceAndPricingOneOfOneone.ts +1 -0
  26. package/openapi/gen/models/index.ts +21 -0
  27. package/openapi/gen/models/listBaseModels200.ts +5 -0
  28. package/openapi/gen/models/listModelVersions200.ts +7 -0
  29. package/openapi/gen/models/listModelVersionsParams.ts +5 -0
  30. package/openapi/gen/models/listProjectModels200.ts +7 -0
  31. package/openapi/gen/models/listProjectModelsParams.ts +5 -0
  32. package/openapi/gen/models/model.ts +16 -0
  33. package/openapi/gen/models/modelArchivedAt.ts +2 -0
  34. package/openapi/gen/models/modelDescription.ts +2 -0
  35. package/openapi/gen/models/modelId.ts +2 -0
  36. package/openapi/gen/models/modelVersion.ts +9 -0
  37. package/openapi/gen/models/modelVersionId.ts +2 -0
  38. package/openapi/gen/models/pipelineGraphSnapshotGraphNodesItemOneOfThreeoneSettingsAudienceAndPricingOneOfOneone.ts +1 -0
  39. package/openapi/gen/models/runCost.ts +7 -0
  40. package/openapi/gen/models/validatePipelineGraphBodyGraphNodesItemOneOfThreeoneSettingsAudienceAndPricingOneOfOneone.ts +1 -0
  41. package/package.json +2 -1
  42. package/skills/catalog.json +22 -0
  43. package/skills/{SKILL.md → toloka-build/SKILL.md} +2 -2
  44. package/skills/{references → toloka-build/references}/workflow-and-cli.md +26 -5
  45. package/skills/toloka-report-issue/SKILL.md +25 -0
  46. package/skills/toloka-report-issue/references/report-template.md +34 -0
  47. package/src/cli/analytics.ts +53 -1
  48. package/src/cli/data.ts +148 -25
  49. package/src/cli/file-system.ts +34 -0
  50. package/src/cli/format-error.ts +19 -0
  51. package/src/cli/init.ts +149 -194
  52. package/src/cli/models.ts +188 -0
  53. package/src/cli/program.ts +202 -22
  54. package/src/cli/report.ts +144 -0
  55. package/src/cli/skill.ts +363 -0
  56. package/src/client.ts +109 -35
  57. package/src/errors.ts +25 -10
  58. package/src/pipeline-graph-v1.contract.json +5 -1
  59. package/src/transport.ts +16 -13
  60. /package/skills/{references → toloka-build/references}/node-semantics.md +0 -0
@@ -0,0 +1,9 @@
1
+ import type { BaseModelIdProperty } from './baseModelIdProperty';
2
+
3
+ export interface BaseModel {
4
+ id: BaseModelIdProperty;
5
+ displayName: string;
6
+ provider: string;
7
+ upstreamModel: string;
8
+ upstreamRevision: string;
9
+ }
@@ -0,0 +1,2 @@
1
+
2
+ export type BaseModelId = 'qwen3-4b' | 'qwen3-8b' | 'qwen3-32b' | 'qwen3-235b';
@@ -0,0 +1,2 @@
1
+
2
+ export type BaseModelIdProperty = 'qwen3-4b' | 'qwen3-8b' | 'qwen3-32b' | 'qwen3-235b';
@@ -1,4 +1,6 @@
1
+ import type { CreateDatasetBodyProfile } from './createDatasetBodyProfile';
1
2
 
2
3
  export type CreateDatasetBody = {
3
4
  name?: string;
5
+ profile?: CreateDatasetBodyProfile;
4
6
  };
@@ -0,0 +1,2 @@
1
+
2
+ export type CreateDatasetBodyProfile = 'chat-sft' | 'instruction';
@@ -1,2 +1,2 @@
1
1
 
2
- export type CreateDatasetUploadBodyFormat = 'json' | 'csv';
2
+ export type CreateDatasetUploadBodyFormat = 'json' | 'csv' | 'jsonl';
@@ -0,0 +1,8 @@
1
+ import type { CreateProjectModelBodyDescription } from './createProjectModelBodyDescription';
2
+ import type { BaseModelId } from './baseModelId';
3
+
4
+ export type CreateProjectModelBody = {
5
+ name: string;
6
+ description?: CreateProjectModelBodyDescription;
7
+ baseModelId: BaseModelId;
8
+ };
@@ -0,0 +1,2 @@
1
+
2
+ export type CreateProjectModelBodyDescription = string | null;
@@ -1,10 +1,12 @@
1
1
  import type { DatasetId } from './datasetId';
2
2
  import type { ProjectId } from './projectId';
3
+ import type { DatasetProfile } from './datasetProfile';
3
4
 
4
5
  export interface Dataset {
5
6
  id: DatasetId;
6
7
  projectId: ProjectId;
7
8
  name: string;
8
9
  hidden: boolean;
10
+ profile: DatasetProfile;
9
11
  createdAt: string;
10
12
  }
@@ -0,0 +1,3 @@
1
+ import type { DatasetProfileStamp } from './datasetProfileStamp';
2
+
3
+ export type DatasetProfile = DatasetProfileStamp | null;
@@ -0,0 +1,6 @@
1
+ import type { DatasetProfileStampName } from './datasetProfileStampName';
2
+
3
+ export interface DatasetProfileStamp {
4
+ name: DatasetProfileStampName;
5
+ version: number;
6
+ }
@@ -0,0 +1,2 @@
1
+
2
+ export type DatasetProfileStampName = 'chat-sft' | 'instruction';
@@ -6,4 +6,5 @@ export type GenerationNodeSettingsAudienceAndPricingOneOfOneone = {
6
6
  generationModelId?: GenerationNodeSettingsAudienceAndPricingOneOfOneoneGenerationModelId;
7
7
  reasoningEffort?: GenerationNodeSettingsAudienceAndPricingOneOfOneoneReasoningEffort;
8
8
  llmInstruction?: string;
9
+ maxCostPerAttempt: number;
9
10
  };
@@ -19,6 +19,9 @@ export * from './attachPipelineDatasetBodyItemFilterFieldValuesItemSourcesItem';
19
19
  export * from './attachPipelineDatasetBodyItemFilterFieldValuesItemSourcesItemOneOf';
20
20
  export * from './attachPipelineDatasetBodyItemFilterFieldValuesItemSourcesItemOneOfTwo';
21
21
  export * from './attachPipelineDatasetBodyItemFilterFieldValuesItemValue';
22
+ export * from './baseModel';
23
+ export * from './baseModelId';
24
+ export * from './baseModelIdProperty';
22
25
  export * from './checkJob';
23
26
  export * from './checkJobError';
24
27
  export * from './checkJobResult';
@@ -68,6 +71,7 @@ export * from './codeNodeSettingsFieldProxiesInputItem';
68
71
  export * from './codeNodeSettingsFieldProxiesOutputItem';
69
72
  export * from './copyPipelineBody';
70
73
  export * from './createDatasetBody';
74
+ export * from './createDatasetBodyProfile';
71
75
  export * from './createDatasetExportBody';
72
76
  export * from './createDatasetField200';
73
77
  export * from './createDatasetFieldBody';
@@ -95,6 +99,8 @@ export * from './createProjectBody';
95
99
  export * from './createProjectBodyDeliveryOrderId';
96
100
  export * from './createProjectFileUpload200';
97
101
  export * from './createProjectFileUploadBody';
102
+ export * from './createProjectModelBody';
103
+ export * from './createProjectModelBodyDescription';
98
104
  export * from './createdDatasetFields';
99
105
  export * from './currentUser';
100
106
  export * from './currentUserEmail';
@@ -111,6 +117,9 @@ export * from './datasetItem';
111
117
  export * from './datasetItemCurrentSubmissionId';
112
118
  export * from './datasetItemDuplicateOfSubmissionId';
113
119
  export * from './datasetItemId';
120
+ export * from './datasetProfile';
121
+ export * from './datasetProfileStamp';
122
+ export * from './datasetProfileStampName';
114
123
  export * from './estimatePipelineCostBody';
115
124
  export * from './estimatePipelineCostBodyItemFilter';
116
125
  export * from './estimatePipelineCostBodyItemFilterFieldSourcesItem';
@@ -245,10 +254,13 @@ export * from './jsonSchema';
245
254
  export * from './jsonSchemaAdditionalProperties';
246
255
  export * from './jsonSchemaType';
247
256
  export * from './jsonSchemaTypeAnyOfItem';
257
+ export * from './listBaseModels200';
248
258
  export * from './listDatasetFields200';
249
259
  export * from './listDatasetFieldsParams';
250
260
  export * from './listDatasetItems200';
251
261
  export * from './listDatasetItemsParams';
262
+ export * from './listModelVersions200';
263
+ export * from './listModelVersionsParams';
252
264
  export * from './listPipelineChecks200';
253
265
  export * from './listPipelineRunItems200';
254
266
  export * from './listPipelineRunItemsParams';
@@ -257,6 +269,8 @@ export * from './listPipelineRunsParams';
257
269
  export * from './listProjectDatasets200';
258
270
  export * from './listProjectDatasetsParams';
259
271
  export * from './listProjectFiles200';
272
+ export * from './listProjectModels200';
273
+ export * from './listProjectModelsParams';
260
274
  export * from './listProjectPipelines200';
261
275
  export * from './listProjectPipelinesParams';
262
276
  export * from './listProjectSecrets200';
@@ -273,6 +287,12 @@ export * from './matchNodeSettingsConditionsItemPredicatesItemOperator';
273
287
  export * from './matchNodeSettingsConditionsItemPredicatesItemValue';
274
288
  export * from './matchNodeSettingsFieldProxies';
275
289
  export * from './matchNodeSettingsFieldProxiesInputItem';
290
+ export * from './model';
291
+ export * from './modelArchivedAt';
292
+ export * from './modelDescription';
293
+ export * from './modelId';
294
+ export * from './modelVersion';
295
+ export * from './modelVersionId';
276
296
  export * from './pagination';
277
297
  export * from './patchPipelineNodeBody';
278
298
  export * from './patchPipelineNodeBodySettings';
@@ -691,6 +711,7 @@ export * from './rootNodeSettingsItemFilterFieldValuesItemSourcesItemOneOfTwo';
691
711
  export * from './rootNodeSettingsItemFilterFieldValuesItemValue';
692
712
  export * from './rootNodeSettingsStartedFieldProxies';
693
713
  export * from './rootNodeSettingsStartedFieldProxiesOutputItem';
714
+ export * from './runCost';
694
715
  export * from './runId';
695
716
  export * from './runItem';
696
717
  export * from './runItemId';
@@ -0,0 +1,5 @@
1
+ import type { BaseModel } from './baseModel';
2
+
3
+ export type ListBaseModels200 = {
4
+ baseModels: BaseModel[];
5
+ };
@@ -0,0 +1,7 @@
1
+ import type { ModelVersion } from './modelVersion';
2
+ import type { Pagination } from './pagination';
3
+
4
+ export type ListModelVersions200 = {
5
+ versions: ModelVersion[];
6
+ pagination: Pagination;
7
+ };
@@ -0,0 +1,5 @@
1
+
2
+ export type ListModelVersionsParams = {
3
+ limit?: number;
4
+ offset?: number;
5
+ };
@@ -0,0 +1,7 @@
1
+ import type { Model } from './model';
2
+ import type { Pagination } from './pagination';
3
+
4
+ export type ListProjectModels200 = {
5
+ models: Model[];
6
+ pagination: Pagination;
7
+ };
@@ -0,0 +1,5 @@
1
+
2
+ export type ListProjectModelsParams = {
3
+ limit?: number;
4
+ offset?: number;
5
+ };
@@ -0,0 +1,16 @@
1
+ import type { ModelId } from './modelId';
2
+ import type { ProjectId } from './projectId';
3
+ import type { ModelDescription } from './modelDescription';
4
+ import type { BaseModelId } from './baseModelId';
5
+ import type { ModelArchivedAt } from './modelArchivedAt';
6
+
7
+ export interface Model {
8
+ id: ModelId;
9
+ projectId: ProjectId;
10
+ name: string;
11
+ description: ModelDescription;
12
+ baseModelId: BaseModelId;
13
+ archivedAt: ModelArchivedAt;
14
+ createdAt: string;
15
+ updatedAt: string;
16
+ }
@@ -0,0 +1,2 @@
1
+
2
+ export type ModelArchivedAt = string | null;
@@ -0,0 +1,2 @@
1
+
2
+ export type ModelDescription = string | null;
@@ -0,0 +1,2 @@
1
+
2
+ export type ModelId = string;
@@ -0,0 +1,9 @@
1
+ import type { ModelVersionId } from './modelVersionId';
2
+ import type { ModelId } from './modelId';
3
+
4
+ export interface ModelVersion {
5
+ id: ModelVersionId;
6
+ modelId: ModelId;
7
+ version: string;
8
+ createdAt: string;
9
+ }
@@ -0,0 +1,2 @@
1
+
2
+ export type ModelVersionId = string;
@@ -6,4 +6,5 @@ export type PipelineGraphSnapshotGraphNodesItemOneOfThreeoneSettingsAudienceAndP
6
6
  generationModelId?: PipelineGraphSnapshotGraphNodesItemOneOfThreeoneSettingsAudienceAndPricingOneOfOneoneGenerationModelId;
7
7
  reasoningEffort?: PipelineGraphSnapshotGraphNodesItemOneOfThreeoneSettingsAudienceAndPricingOneOfOneoneReasoningEffort;
8
8
  llmInstruction?: string;
9
+ maxCostPerAttempt: number;
9
10
  };
@@ -0,0 +1,7 @@
1
+ import type { RunId } from './runId';
2
+
3
+ export interface RunCost {
4
+ runId: RunId;
5
+ computedAt: string;
6
+ total: string;
7
+ }
@@ -6,4 +6,5 @@ export type ValidatePipelineGraphBodyGraphNodesItemOneOfThreeoneSettingsAudience
6
6
  generationModelId?: ValidatePipelineGraphBodyGraphNodesItemOneOfThreeoneSettingsAudienceAndPricingOneOfOneoneGenerationModelId;
7
7
  reasoningEffort?: ValidatePipelineGraphBodyGraphNodesItemOneOfThreeoneSettingsAudienceAndPricingOneOfOneoneReasoningEffort;
8
8
  llmInstruction?: string;
9
+ maxCostPerAttempt: number;
9
10
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toloka-platform/sdk",
3
- "version": "0.1.0-preview.4",
3
+ "version": "0.1.0-preview.6",
4
4
  "private": false,
5
5
  "description": "Preview. Build, inspect, and operate Toloka pipeline projects as TypeScript source. The public API may change.",
6
6
  "license": "Apache-2.0",
@@ -32,6 +32,7 @@
32
32
  "build": "bun ./scripts/build-cli.ts ./dist/cli",
33
33
  "generate": "orval --config ./openapi/orval.config.js",
34
34
  "prepack": "bun run build",
35
+ "sync-skill-catalog": "bun ./scripts/sync-skill-catalog.ts",
35
36
  "test": "vitest run",
36
37
  "typecheck": "tsc --noEmit"
37
38
  },
@@ -0,0 +1,22 @@
1
+ {
2
+ "skills": [
3
+ {
4
+ "id": "toloka-build",
5
+ "name": "Build Toloka pipelines as code",
6
+ "description": "Build, inspect, and change Toloka platform pipeline projects as TypeScript source with @toloka-platform/sdk and toloka. Use when the user wants to create, adopt, inspect, plan, or apply a pipeline project as code.",
7
+ "tags": ["pipelines", "authoring", "sdk"],
8
+ "version": "0.1.0-preview.6",
9
+ "digest": "d45d1124d27e19ee43c260ddf0c259ccdc343c5d641c2aeb538d6fedaeb99183",
10
+ "files": ["SKILL.md", "references/node-semantics.md", "references/workflow-and-cli.md"]
11
+ },
12
+ {
13
+ "id": "toloka-report-issue",
14
+ "name": "Report a Toloka problem",
15
+ "description": "Report a problem with the Toloka platform, CLI, or SDK as a redacted Markdown issue report sent through the toloka CLI only after explicit approval. Use when the user hits unexpected behavior, an error, or a bug and wants Toloka engineers to investigate.",
16
+ "tags": ["support", "issue", "bug", "report"],
17
+ "version": "0.1.0-preview.6",
18
+ "digest": "b71d06333786826edd51b909dfe8a20633870f235d03df4aae83d20c26e99205",
19
+ "files": ["SKILL.md", "references/report-template.md"]
20
+ }
21
+ ]
22
+ }
@@ -46,7 +46,7 @@ Import authoring helpers from `@toloka-platform/sdk`.
46
46
 
47
47
  Let constructors mint IDs for new declarations. Preserve `id` options generated by `toloka import`, but never invent or hand-edit raw `fp_…`, `ds.…`, `pl.…`, or `pp.…` values in authored settings. Never add a `layout` block: layout is not authored, existing layout is preserved, and the server supplies defaults.
48
48
 
49
- Read [node semantics](references/node-semantics.md) before selecting or configuring a node. Use the published [face image collection example](../examples/face-image-collection/) as a concrete authoring pattern.
49
+ Read [node semantics](references/node-semantics.md) before selecting or configuring a node. Use `node_modules/@toloka-platform/sdk/examples/face-image-collection/` as a concrete authoring pattern.
50
50
 
51
51
  ## Get human-work settings right the first time
52
52
 
@@ -66,7 +66,7 @@ A successful `toloka validate` is necessary, not proof the pipeline can be launc
66
66
 
67
67
  ## Keep data and credentials out of source
68
68
 
69
- - Never put dataset items in pipeline source or `toloka.json`. After apply has created or resolved the dataset, upload JSONL objects with `toloka dataset upload <dataset> <file>`. If a later upload fails as schema-incompatible, run `toloka dataset fields <dataset>` and copy the printed `field()` declarations into source.
69
+ - Never put dataset items in pipeline source or `toloka.json`. After apply has created or resolved the dataset, upload `.json`, `.jsonl`, or `.csv` rows with `toloka dataset upload <dataset> <file>`. If a later upload fails as schema-incompatible, run `toloka dataset fields <dataset>` and copy the printed `field()` declarations into source.
70
70
  - Put secret references in node settings, but never secret values. Set values through stdin with `toloka secret set <name>`, or use `toloka secret set <name> --from-env <variable>`.
71
71
 
72
72
  ## Credentials
@@ -33,9 +33,9 @@ bun add --dev @toloka-platform/sdk
33
33
  toloka init
34
34
  ```
35
35
 
36
- `init` does not require a selected project. It checks that `@toloka-platform/sdk` is declared in `dependencies` or `devDependencies`, then writes a Claude skill for `.claude/`, a Cursor rule when `.cursor/rules/` exists, and a marked block in an existing `AGENTS.md`; with no agent configuration, it creates the Claude skill and `AGENTS.md`. If a project is already selected through `--project-id`, `TOLOKA_PROJECT_ID` / `POTATO_PROJECT_ID`, `toloka.json`, or the machine registry, it also writes `toloka.json` when missing.
36
+ `init` does not require a selected project. It checks that `@toloka-platform/sdk` is declared in `dependencies` or `devDependencies`, then maintains one `<toloka>` Agent Bootstrap block in `AGENTS.md` and writes minimal pointers to it: a Claude skill at `.claude/skills/toloka-bootstrap/SKILL.md` when `.claude/` exists (or when no agent configuration exists at all) and an always-applied Cursor rule at `.cursor/rules/toloka-bootstrap.mdc` when `.cursor/rules/` exists. If a project is already selected through `--project-id`, `TOLOKA_PROJECT_ID` / `POTATO_PROJECT_ID`, `toloka.json`, or the machine registry, it also writes `toloka.json` when missing.
37
37
 
38
- The generated entry points contain the core read, edit, validate, plan, and apply loop and point back to the fuller references in this package. Every `toloka` command except `init` compares the recorded skill-content digest with the installed SDK and warns on stderr when they differ. The warning never blocks the command; re-run `toloka init` to refresh the pointers.
38
+ The bootstrap is small: it tells an agent to run `toloka --help`, search the bundled Skill Catalog with `toloka skill search <query>`, install the match with `toloka skill install <skill-id>`, and read `.agents/skills/<skill-id>/SKILL.md`. This skill is that installed copy. Commands warn on stderr when a generated legacy entry point is still present or the recorded bootstrap version differs from the installed SDK. Help, `init`, `report`, `project url`, and version invocations skip this checkout-dependent warning. The warning never blocks a command; re-run `toloka init` to refresh the bootstrap and its pointers.
39
39
 
40
40
  ## Store credentials once
41
41
 
@@ -71,13 +71,16 @@ require `toloka login` first because they read and write the credentials file. W
71
71
  project ID in this order: `--project-id`, `TOLOKA_PROJECT_ID`, `POTATO_PROJECT_ID`, `toloka.json`,
72
72
  then the machine registry `current`.
73
73
 
74
- Anonymous command telemetry is on by default (`sdk_cli_command_completed` / `sdk_cli_command_failed`). Set `TOLOKA_TELEMETRY=0` or `DO_NOT_TRACK=1` to disable it. CI is off unless `TOLOKA_TELEMETRY=1`.
74
+ Anonymous command telemetry is on by default (`sdk_cli_command_completed` / `sdk_cli_command_failed`). `toloka report` uses the same PostHog client to send explicitly approved Markdown in `sdk_cli_issue_report_submitted`. Set `TOLOKA_TELEMETRY=0` or `DO_NOT_TRACK=1` to disable both; CI is off unless `TOLOKA_TELEMETRY=1`.
75
75
 
76
76
  All commands accept `--source-root <directory>`. Prefer running from the source root so paths and diffs stay obvious. `init` does not walk up: it binds the working directory or `--source-root` only.
77
77
 
78
78
  The real command surface is:
79
79
 
80
80
  ```text
81
+ toloka version
82
+ toloka -v
83
+ toloka --version
81
84
  toloka login
82
85
  toloka logout
83
86
  toloka auth-status
@@ -85,6 +88,7 @@ toloka project list
85
88
  toloka project add [alias] [projectId]
86
89
  toloka project switch <alias>
87
90
  toloka project current
91
+ toloka project url
88
92
  toloka project remove <alias>
89
93
  toloka project create [alias] [--name <name>] [--team-id <id>]
90
94
  toloka init
@@ -105,12 +109,29 @@ toloka pipeline runs [name] [--limit <n>]
105
109
  toloka pipeline cost [name] [--item-limit <n>]
106
110
  toloka pipeline results <runId> [--limit <n>] [--failed]
107
111
  toloka pipeline cancel <runId>
112
+ toloka base-model list [--json]
113
+ toloka base-model get <id> [--json]
114
+ toloka model list [--json]
115
+ toloka model get <name-or-id> [--json]
116
+ toloka model versions <name-or-id> [--json]
117
+ toloka model create <name> --base <base-model-id> [--description <text>] [--json]
118
+ toloka model archive <name-or-id> [--json]
119
+ toloka skill list [--json]
120
+ toloka skill search <query> [--json]
121
+ toloka skill install <skill-id> [--force]
122
+ toloka report <markdown> [--authored-by human|agent] [--confirm]
108
123
  ```
109
124
 
110
125
  Select the platform project with `toloka project add` or `toloka project create` before `import`, `plan`, or `apply`. `init` may run first, and `import` uses the selected project when the id is omitted.
111
126
 
127
+ `toloka project url` prints only the selected project's platform UI URL. Use it when the user needs a working link to inspect the live project.
128
+
112
129
  `toloka pipeline cost [name] [--item-limit <n>]` forecasts what a run of a live pipeline would bill. It does not start a run and does not change the graph. Name the live pipeline or id; a TTY may pick among several. The typed client equivalent is `client.pipelines.estimateCost({ pipelineId, itemLimit? })`.
113
130
 
131
+ ## Manage model checkpoints
132
+
133
+ The global Base Model Catalog is read-only and uses `toloka base-model`. `base-model list` prints aligned ID, name, provider, and upstream-model columns by default. `toloka model` manages project-owned lineages; creation requires one catalog `baseModelId` and creates metadata without a Model Version. Every Base Model and Model command accepts `--json` for machine-readable output. Model Version upload, validation, and download commands are deferred until the separate upload-processing contract is implemented.
134
+
114
135
  ## Adopt an existing live project
115
136
 
116
137
  1. Run `toloka init` in the intended source root if the agent entry points are not installed yet.
@@ -176,7 +197,7 @@ Declare the fields in source, then upload rows:
176
197
  toloka dataset upload <dataset> <file>
177
198
  ```
178
199
 
179
- The input file is JSONL: each non-empty line must parse as one JSON object. The dataset does not have to exist yet: when a pipeline in source binds it, upload creates it and declares that pipeline's columns, so rows land in real columns rather than in the raw `uploaded` blob. Upload refuses when no pipeline in source declares a name because it would have no column names to map onto. An id-shaped argument is never created; upload fails when that dataset id does not exist in the project. Upload appends items; apply never uploads, replaces, or deletes rows. Duplicate live names must be addressed by id.
200
+ The CLI infers the input format from its extension and uploads the original bytes without conversion: `.json` is an array of row objects, `.jsonl` has one object per non-empty line, and `.csv` uses its header row as field names with every value ingested as a string. JSONL is validated locally before upload. If transfer or finalization fails, the CLI cancels the started upload before returning the error, so another upload can start immediately and may reuse the same filename. The dataset does not have to exist yet: when a pipeline in source binds it, upload creates it and declares that pipeline's columns, so rows land in real columns rather than in the raw `uploaded` blob. Upload refuses when no pipeline in source declares a name because it would have no column names to map onto. An id-shaped argument is never created; upload fails when that dataset id does not exist in the project. Upload appends items; applying source never deletes them.
180
201
 
181
202
  If a later upload fails with a schema-incompatibility error, inspect the inferred schema from the first successful upload:
182
203
 
@@ -254,4 +275,4 @@ Read the returned path and reason. Check connection endpoints, duplicate or unkn
254
275
 
255
276
  ## Use the shipped example
256
277
 
257
- Read [the face image collection pipeline](../../examples/face-image-collection/pipeline.ts), its `fields.ts`, and its `nodes/` modules for a real composition of `field`, `root`, `generation`, `code`, `connect`, and `definePipeline`. Copy its source organization, not its task-specific settings.
278
+ Read `node_modules/@toloka-platform/sdk/examples/face-image-collection/pipeline.ts`, its `fields.ts`, and its `nodes/` modules for a real composition of `field`, `root`, `generation`, `code`, `connect`, and `definePipeline`. Copy its source organization, not its task-specific settings.
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: toloka-report-issue
3
+ description: Report a problem with the Toloka platform, CLI, or SDK as a redacted Markdown issue report sent through the toloka CLI only after explicit approval. Use when the user hits unexpected behavior, an error, or a bug and wants Toloka engineers to investigate.
4
+ ---
5
+
6
+ # Report a Toloka problem
7
+
8
+ Use this skill when Toloka platform, CLI, or SDK behavior blocks the user's work and they want Toloka engineers to investigate. The result is one Markdown issue report sent through the `toloka` CLI. Nothing leaves the machine until the user has reviewed the complete report and approved it.
9
+
10
+ ## Workflow
11
+
12
+ 1. Collect verified facts: what the user ran, what they expected, what happened, and any relevant project, pipeline, dataset, run, thread, or request IDs. Ask for missing reproduction steps or reproduce the failure with real commands. Never invent a timeline, command output, or identifier.
13
+ 2. Copy [the template](references/report-template.md), preserve its section order, and replace the example with the user's evidence. Write `None` for sections that do not apply. The final UTF-8 Markdown file must not exceed 256 KiB.
14
+ 3. Redact before previewing. Include only evidence the user selected. Replace every API key, token, password, cookie, connection string, or personal value with a marker such as `[REDACTED:api-key]`, and list each replacement under Redactions without the original value. Never read environment variables, credential files, shell history, or logs the user did not name.
15
+ 4. Show the user the exact complete Markdown file and ask whether to send it. If they decline or request changes, do not submit; revise the file and ask again.
16
+ 5. Only after approval, run `toloka report <report.md> --authored-by agent --confirm`. The command previews the same Markdown, submits it as one PostHog event, flushes delivery, and prints `Submitted issue report: <id>` only after PostHog accepts the flush.
17
+ 6. Return the printed report ID to the user. If submission fails, keep the Markdown file, report the exact error, and do not claim success or retry without approval.
18
+
19
+ ## Boundaries
20
+
21
+ - Submit only the Markdown file. The command has no attachment or structured-reference flags; put relevant IDs and text evidence in the report itself.
22
+ - The event contains the complete Markdown, report ID, UTF-8 byte length, declared authorship, platform origin, and the standard pseudonymous CLI telemetry context. It never reads or sends the API key.
23
+ - `--authored-by agent` records who prepared the report. It does not authenticate or grant access.
24
+ - Issue reporting is unavailable when CLI telemetry is disabled. Do not bypass that setting.
25
+ - Use the CLI, not the SDK or raw PostHog API. The user-visible preview and explicit approval are the consent boundary.
@@ -0,0 +1,34 @@
1
+ # Issue Report: `toloka apply` returns HTTP 500 for the cat labeling project
2
+
3
+ ## Summary
4
+
5
+ `toloka apply` fails with HTTP 500 after `toloka validate` passed, so the edited pipeline never reaches the platform.
6
+
7
+ ## Steps to reproduce
8
+
9
+ 1. Change the labeler instruction in `pipelines/cat-labeling/nodes/annotate-cats/node.ts`.
10
+ 2. Run `toloka validate`; it reports no issues.
11
+ 3. Run `toloka apply`.
12
+
13
+ ## Expected behavior
14
+
15
+ `toloka apply` writes the new graph version and prints the changed node.
16
+
17
+ ## Actual behavior
18
+
19
+ The CLI exits 1 with `Potato API request failed with status 500`. The same command failed three times between 09:12 and 09:20 UTC; `toloka plan` still shows the pending change.
20
+
21
+ ## Relevant IDs
22
+
23
+ - Project: pp.0192f3a4-5b6c-7d8e-9f01-23456789abcd
24
+ - Pipeline: pl.0192f3a4-5b6c-7d8e-9f01-23456789abce
25
+ - Request: None supplied
26
+
27
+ ## Environment
28
+
29
+ - toloka CLI 0.1.0-preview.6 (`toloka --version`), Bun 1.4.0, macOS 15
30
+ - Platform: https://platform.toloka.ai
31
+
32
+ ## Redactions
33
+
34
+ - The API key in the user-selected command output was replaced with `[REDACTED:api-key]`.
@@ -1,3 +1,4 @@
1
+ import { assert } from "es-toolkit";
1
2
  import { randomUUID } from "node:crypto";
2
3
  import { chmod, readFile, writeFile } from "node:fs/promises";
3
4
  import { dirname, join } from "node:path";
@@ -28,13 +29,22 @@ export type CliAnalyticsCapture = {
28
29
  readonly error?: unknown;
29
30
  };
30
31
 
32
+ export type IssueReportSubmission = {
33
+ readonly reportId: string;
34
+ readonly reportText: string;
35
+ readonly authoredBy: "human" | "agent";
36
+ readonly platform: string;
37
+ };
38
+
31
39
  export type CliAnalytics = {
32
40
  readonly shouldIdentify: boolean;
41
+ readonly issueReportingEnabled: boolean;
33
42
  readonly identifyCurrentUser: (user: {
34
43
  readonly id: string;
35
44
  readonly email: string | null;
36
45
  }) => void;
37
46
  readonly captureCommand: (event: CliAnalyticsCapture) => void;
47
+ readonly submitIssueReport: (report: IssueReportSubmission) => Promise<void>;
38
48
  readonly shutdown: () => Promise<void>;
39
49
  };
40
50
 
@@ -46,6 +56,8 @@ export type PosthogLike = {
46
56
  disableGeoip: boolean;
47
57
  }) => void;
48
58
  alias: (event: { distinctId: string; alias: string }) => void;
59
+ flush: () => Promise<void>;
60
+ on?: (event: "error", listener: (error: Error) => void) => void;
49
61
  shutdown: (shutdownTimeoutMs?: number) => Promise<void>;
50
62
  };
51
63
 
@@ -86,6 +98,7 @@ const COMMAND_GROUPS: Readonly<Record<string, Readonly<Record<string, true>>>> =
86
98
  },
87
99
  dataset: { list: true, fields: true, load: true, upload: true },
88
100
  secret: { set: true },
101
+ skill: { list: true, search: true, install: true },
89
102
  };
90
103
 
91
104
  const ROOT_COMMANDS: Readonly<Record<string, true>> = {
@@ -99,6 +112,8 @@ const ROOT_COMMANDS: Readonly<Record<string, true>> = {
99
112
  plan: true,
100
113
  status: true,
101
114
  validate: true,
115
+ report: true,
116
+ version: true,
102
117
  whoami: true,
103
118
  };
104
119
 
@@ -116,6 +131,7 @@ const nameFromTokens = (tokens: readonly string[]): string => {
116
131
  };
117
132
 
118
133
  export function commandNameFromArgv(argv: readonly string[]): string {
134
+ if (argv.includes("-v") || argv.includes("--version")) return "version";
119
135
  const tokens: string[] = [];
120
136
  for (let index = 0; index < argv.length; index += 1) {
121
137
  const token = argv[index];
@@ -161,8 +177,12 @@ const readAnonymousId = async (environment: CliEnvironment): Promise<string> =>
161
177
 
162
178
  const noopAnalytics = (): CliAnalytics => ({
163
179
  shouldIdentify: false,
180
+ issueReportingEnabled: false,
164
181
  identifyCurrentUser() {},
165
182
  captureCommand() {},
183
+ async submitIssueReport() {
184
+ assert(false, "Issue reporting is disabled. Re-run with TOLOKA_TELEMETRY=1.");
185
+ },
166
186
  async shutdown() {},
167
187
  });
168
188
 
@@ -177,6 +197,11 @@ export function createCliAnalytics(options: {
177
197
  let client = options.client;
178
198
  let distinctId = options.distinctId;
179
199
  let identifiedUserId: string | undefined;
200
+ const deliveryErrors: Error[] = [];
201
+ const captureDeliveryError = (error: Error) => {
202
+ deliveryErrors.push(error);
203
+ };
204
+ client?.on?.("error", captureDeliveryError);
180
205
 
181
206
  const ensure = async () => {
182
207
  if (client !== undefined && distinctId !== undefined) return;
@@ -186,7 +211,7 @@ export function createCliAnalytics(options: {
186
211
  flushAt: 1,
187
212
  flushInterval: 0,
188
213
  });
189
- created.on("error", () => {});
214
+ created.on("error", captureDeliveryError);
190
215
  client = created;
191
216
  }
192
217
  distinctId ??= await readAnonymousId(environment);
@@ -202,6 +227,7 @@ export function createCliAnalytics(options: {
202
227
  let queue: Promise<void> = ensure().catch(() => {});
203
228
 
204
229
  return {
230
+ issueReportingEnabled: true,
205
231
  shouldIdentify: true,
206
232
  identifyCurrentUser(user) {
207
233
  queue = queue
@@ -252,6 +278,32 @@ export function createCliAnalytics(options: {
252
278
  })
253
279
  .catch(() => {});
254
280
  },
281
+ submitIssueReport(report) {
282
+ const submission = queue.then(async () => {
283
+ assert(client && distinctId, "PostHog issue reporting could not be initialized.");
284
+ deliveryErrors.length = 0;
285
+ client.capture({
286
+ distinctId,
287
+ event: "sdk_cli_issue_report_submitted",
288
+ disableGeoip: true,
289
+ properties: {
290
+ ...sharedProperties(),
291
+ report_id: report.reportId,
292
+ report_text: report.reportText,
293
+ report_length_bytes: new TextEncoder().encode(report.reportText).length,
294
+ authored_by: report.authoredBy,
295
+ platform: report.platform,
296
+ $process_person_profile: false,
297
+ },
298
+ });
299
+ await client.flush();
300
+ const reportError = deliveryErrors[0];
301
+ deliveryErrors.length = 0;
302
+ if (reportError !== undefined) throw reportError;
303
+ });
304
+ queue = submission.catch(() => {});
305
+ return submission;
306
+ },
255
307
  async shutdown() {
256
308
  try {
257
309
  await queue;