@toloka-platform/sdk 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/cli/toloka.js +153 -151
  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/cli.md +17 -0
  6. package/openapi/gen/api.ts +142 -0
  7. package/openapi/gen/models/batchInferenceMode.ts +3 -0
  8. package/openapi/gen/models/batchInferenceModeOneOf.ts +4 -0
  9. package/openapi/gen/models/batchInferenceModel.ts +4 -0
  10. package/openapi/gen/models/batchInferenceModelOneOf.ts +6 -0
  11. package/openapi/gen/models/batchInferenceModelOneOfBaseModelId.ts +2 -0
  12. package/openapi/gen/models/batchInferenceModelOneOfThree.ts +5 -0
  13. package/openapi/gen/models/batchInferenceRun.ts +35 -0
  14. package/openapi/gen/models/batchInferenceRunBlockedReason.ts +2 -0
  15. package/openapi/gen/models/batchInferenceRunChargedAmount.ts +2 -0
  16. package/openapi/gen/models/batchInferenceRunError.ts +3 -0
  17. package/openapi/gen/models/batchInferenceRunErrorAnyOf.ts +6 -0
  18. package/openapi/gen/models/batchInferenceRunErrorAnyOfCode.ts +2 -0
  19. package/openapi/gen/models/batchInferenceRunId.ts +2 -0
  20. package/openapi/gen/models/batchInferenceRunMessage.ts +2 -0
  21. package/openapi/gen/models/batchInferenceRunOutput.ts +9 -0
  22. package/openapi/gen/models/batchInferenceRunOutputType.ts +2 -0
  23. package/openapi/gen/models/batchInferenceRunProgress.ts +3 -0
  24. package/openapi/gen/models/batchInferenceRunProgressAnyOf.ts +7 -0
  25. package/openapi/gen/models/batchInferenceRunProgressAnyOfPhase.ts +2 -0
  26. package/openapi/gen/models/batchInferenceRunProgressAnyOfRequests.ts +5 -0
  27. package/openapi/gen/models/batchInferenceRunQuote.ts +3 -0
  28. package/openapi/gen/models/batchInferenceRunQuoteAnyOf.ts +9 -0
  29. package/openapi/gen/models/batchInferenceRunQuoteAnyOfConfirmBefore.ts +2 -0
  30. package/openapi/gen/models/batchInferenceRunResult.ts +3 -0
  31. package/openapi/gen/models/batchInferenceRunResultAnyOf.ts +12 -0
  32. package/openapi/gen/models/batchInferenceRunResultAnyOfErrorCounts.ts +2 -0
  33. package/openapi/gen/models/batchInferenceRunResultAnyOfErrorSamplesItem.ts +6 -0
  34. package/openapi/gen/models/batchInferenceRunSampling.ts +9 -0
  35. package/openapi/gen/models/batchInferenceRunStatus.ts +2 -0
  36. package/openapi/gen/models/createBatchInferenceRunBody.ts +14 -0
  37. package/openapi/gen/models/createBatchInferenceRunBodyItemFilter.ts +14 -0
  38. package/openapi/gen/models/createBatchInferenceRunBodyItemFilterExcludePartsItem.ts +5 -0
  39. package/openapi/gen/models/createBatchInferenceRunBodyItemFilterFieldSourcesItem.ts +6 -0
  40. package/openapi/gen/models/createBatchInferenceRunBodyItemFilterFieldSourcesItemSourcesItem.ts +4 -0
  41. package/openapi/gen/models/createBatchInferenceRunBodyItemFilterFieldSourcesItemSourcesItemOneOf.ts +5 -0
  42. package/openapi/gen/models/createBatchInferenceRunBodyItemFilterFieldSourcesItemSourcesItemOneOfTwo.ts +5 -0
  43. package/openapi/gen/models/createBatchInferenceRunBodyItemFilterFieldValuesItem.ts +12 -0
  44. package/openapi/gen/models/createBatchInferenceRunBodyItemFilterFieldValuesItemOperator.ts +2 -0
  45. package/openapi/gen/models/createBatchInferenceRunBodyItemFilterFieldValuesItemSourcesItem.ts +4 -0
  46. package/openapi/gen/models/createBatchInferenceRunBodyItemFilterFieldValuesItemSourcesItemOneOf.ts +5 -0
  47. package/openapi/gen/models/createBatchInferenceRunBodyItemFilterFieldValuesItemSourcesItemOneOfTwo.ts +5 -0
  48. package/openapi/gen/models/createBatchInferenceRunBodyItemFilterFieldValuesItemValue.ts +2 -0
  49. package/openapi/gen/models/createBatchInferenceRunBodyItemFilterParts.ts +5 -0
  50. package/openapi/gen/models/createBatchInferenceRunBodyItemFilterSlice.ts +4 -0
  51. package/openapi/gen/models/createBatchInferenceRunBodyOutput.ts +4 -0
  52. package/openapi/gen/models/createBatchInferenceRunBodyOutputOneOf.ts +5 -0
  53. package/openapi/gen/models/createBatchInferenceRunBodyOutputOneOfTwo.ts +5 -0
  54. package/openapi/gen/models/createBatchInferenceRunBodySampling.ts +9 -0
  55. package/openapi/gen/models/datasetExportReportTokensEstimatorVersion.ts +1 -1
  56. package/openapi/gen/models/datasetFieldOperation.ts +2 -1
  57. package/openapi/gen/models/datasetFieldWriteOperation.ts +8 -0
  58. package/openapi/gen/models/datasetFieldWriteOperationProgress.ts +3 -0
  59. package/openapi/gen/models/datasetFieldWriteOperationProgressAnyOf.ts +5 -0
  60. package/openapi/gen/models/index.ts +53 -0
  61. package/openapi/gen/models/listBatchInferenceRuns200.ts +7 -0
  62. package/openapi/gen/models/listBatchInferenceRunsParams.ts +5 -0
  63. package/openapi/gen/models/trainingCostEstimateOneOfInputsTrainingReportAnyOfTokensEstimatorVersion.ts +1 -1
  64. package/openapi/gen/models/trainingCostEstimateOneOfInputsValidationAnyOfReportAnyOfTokensEstimatorVersion.ts +1 -1
  65. package/openapi/gen/models/trainingCostEstimateOneOfTwosevenInputsTrainingReportAnyOfTokensEstimatorVersion.ts +1 -1
  66. package/openapi/gen/models/trainingCostEstimateOneOfTwosevenInputsValidationAnyOfReportAnyOfTokensEstimatorVersion.ts +1 -1
  67. package/openapi/gen/models/trainingRunInputsAnyOfTrainingReportTokensEstimatorVersion.ts +1 -1
  68. package/openapi/gen/models/trainingRunInputsAnyOfValidationAnyOfReportTokensEstimatorVersion.ts +1 -1
  69. package/openapi/gen/models/trainingRunQuoteInputsTrainingReportAnyOfTokensEstimatorVersion.ts +1 -1
  70. package/openapi/gen/models/trainingRunQuoteInputsValidationAnyOfReportAnyOfTokensEstimatorVersion.ts +1 -1
  71. package/package.json +2 -2
  72. package/skills/catalog.json +8 -8
  73. package/skills/toloka-build/references/workflow-and-cli.md +5 -1
  74. package/skills/toloka-fine-tuning/SKILL.md +2 -1
  75. package/skills/toloka-gisting/SKILL.md +3 -2
  76. package/src/cli/analytics.ts +8 -0
  77. package/src/cli/batch-inference.ts +267 -0
  78. package/src/cli/commands/batch-inference.ts +116 -0
  79. package/src/cli/context.ts +14 -0
  80. package/src/cli/models.ts +1 -1
  81. package/src/cli/program.ts +2 -0
  82. package/src/cli/splits.ts +40 -0
  83. package/src/cli/trainings.ts +1 -19
  84. package/src/client.ts +49 -0
@@ -25,6 +25,35 @@ export * from './attachPipelineDatasetBodyItemFilterSlice';
25
25
  export * from './baseModel';
26
26
  export * from './baseModelId';
27
27
  export * from './baseModelIdProperty';
28
+ export * from './batchInferenceMode';
29
+ export * from './batchInferenceModeOneOf';
30
+ export * from './batchInferenceModel';
31
+ export * from './batchInferenceModelOneOf';
32
+ export * from './batchInferenceModelOneOfBaseModelId';
33
+ export * from './batchInferenceModelOneOfThree';
34
+ export * from './batchInferenceRun';
35
+ export * from './batchInferenceRunBlockedReason';
36
+ export * from './batchInferenceRunChargedAmount';
37
+ export * from './batchInferenceRunError';
38
+ export * from './batchInferenceRunErrorAnyOf';
39
+ export * from './batchInferenceRunErrorAnyOfCode';
40
+ export * from './batchInferenceRunId';
41
+ export * from './batchInferenceRunMessage';
42
+ export * from './batchInferenceRunOutput';
43
+ export * from './batchInferenceRunOutputType';
44
+ export * from './batchInferenceRunProgress';
45
+ export * from './batchInferenceRunProgressAnyOf';
46
+ export * from './batchInferenceRunProgressAnyOfPhase';
47
+ export * from './batchInferenceRunProgressAnyOfRequests';
48
+ export * from './batchInferenceRunQuote';
49
+ export * from './batchInferenceRunQuoteAnyOf';
50
+ export * from './batchInferenceRunQuoteAnyOfConfirmBefore';
51
+ export * from './batchInferenceRunResult';
52
+ export * from './batchInferenceRunResultAnyOf';
53
+ export * from './batchInferenceRunResultAnyOfErrorCounts';
54
+ export * from './batchInferenceRunResultAnyOfErrorSamplesItem';
55
+ export * from './batchInferenceRunSampling';
56
+ export * from './batchInferenceRunStatus';
28
57
  export * from './checkJob';
29
58
  export * from './checkJobError';
30
59
  export * from './checkJobResult';
@@ -78,6 +107,25 @@ export * from './codeNodeSettingsFieldProxies';
78
107
  export * from './codeNodeSettingsFieldProxiesInputItem';
79
108
  export * from './codeNodeSettingsFieldProxiesOutputItem';
80
109
  export * from './copyPipelineBody';
110
+ export * from './createBatchInferenceRunBody';
111
+ export * from './createBatchInferenceRunBodyItemFilter';
112
+ export * from './createBatchInferenceRunBodyItemFilterExcludePartsItem';
113
+ export * from './createBatchInferenceRunBodyItemFilterFieldSourcesItem';
114
+ export * from './createBatchInferenceRunBodyItemFilterFieldSourcesItemSourcesItem';
115
+ export * from './createBatchInferenceRunBodyItemFilterFieldSourcesItemSourcesItemOneOf';
116
+ export * from './createBatchInferenceRunBodyItemFilterFieldSourcesItemSourcesItemOneOfTwo';
117
+ export * from './createBatchInferenceRunBodyItemFilterFieldValuesItem';
118
+ export * from './createBatchInferenceRunBodyItemFilterFieldValuesItemOperator';
119
+ export * from './createBatchInferenceRunBodyItemFilterFieldValuesItemSourcesItem';
120
+ export * from './createBatchInferenceRunBodyItemFilterFieldValuesItemSourcesItemOneOf';
121
+ export * from './createBatchInferenceRunBodyItemFilterFieldValuesItemSourcesItemOneOfTwo';
122
+ export * from './createBatchInferenceRunBodyItemFilterFieldValuesItemValue';
123
+ export * from './createBatchInferenceRunBodyItemFilterParts';
124
+ export * from './createBatchInferenceRunBodyItemFilterSlice';
125
+ export * from './createBatchInferenceRunBodyOutput';
126
+ export * from './createBatchInferenceRunBodyOutputOneOf';
127
+ export * from './createBatchInferenceRunBodyOutputOneOfTwo';
128
+ export * from './createBatchInferenceRunBodySampling';
81
129
  export * from './createDatasetBody';
82
130
  export * from './createDatasetBodyProfile';
83
131
  export * from './createDatasetExportBody';
@@ -168,6 +216,9 @@ export * from './datasetFieldSplitAnyOfRecipeAnyOfBalanceByFieldId';
168
216
  export * from './datasetFieldSplitAnyOfRecipeAnyOfSharesItem';
169
217
  export * from './datasetFieldSplitAnyOfStatus';
170
218
  export * from './datasetFieldSplitFillOperation';
219
+ export * from './datasetFieldWriteOperation';
220
+ export * from './datasetFieldWriteOperationProgress';
221
+ export * from './datasetFieldWriteOperationProgressAnyOf';
171
222
  export * from './datasetId';
172
223
  export * from './datasetItem';
173
224
  export * from './datasetItemCurrentSubmissionId';
@@ -356,6 +407,8 @@ export * from './jsonSchemaTypeAnyOfItem';
356
407
  export * from './listAudienceSpecializations200';
357
408
  export * from './listAudienceSpecializationsParams';
358
409
  export * from './listBaseModels200';
410
+ export * from './listBatchInferenceRuns200';
411
+ export * from './listBatchInferenceRunsParams';
359
412
  export * from './listDatasetFields200';
360
413
  export * from './listDatasetFieldsParams';
361
414
  export * from './listDatasetItems200';
@@ -0,0 +1,7 @@
1
+ import type { BatchInferenceRun } from './batchInferenceRun';
2
+ import type { Pagination } from './pagination';
3
+
4
+ export type ListBatchInferenceRuns200 = {
5
+ batchInferenceRuns: BatchInferenceRun[];
6
+ pagination: Pagination;
7
+ };
@@ -0,0 +1,5 @@
1
+
2
+ export type ListBatchInferenceRunsParams = {
3
+ limit?: number;
4
+ offset?: number;
5
+ };
@@ -1,2 +1,2 @@
1
1
 
2
- export type TrainingCostEstimateOneOfInputsTrainingReportAnyOfTokensEstimatorVersion = 'utf16-code-units-div-4-v1' | null;
2
+ export type TrainingCostEstimateOneOfInputsTrainingReportAnyOfTokensEstimatorVersion = 'utf16-code-units-div-4-v1' | 'script-weighted-v1' | null;
@@ -1,2 +1,2 @@
1
1
 
2
- export type TrainingCostEstimateOneOfInputsValidationAnyOfReportAnyOfTokensEstimatorVersion = 'utf16-code-units-div-4-v1' | null;
2
+ export type TrainingCostEstimateOneOfInputsValidationAnyOfReportAnyOfTokensEstimatorVersion = 'utf16-code-units-div-4-v1' | 'script-weighted-v1' | null;
@@ -1,2 +1,2 @@
1
1
 
2
- export type TrainingCostEstimateOneOfTwosevenInputsTrainingReportAnyOfTokensEstimatorVersion = 'utf16-code-units-div-4-v1' | null;
2
+ export type TrainingCostEstimateOneOfTwosevenInputsTrainingReportAnyOfTokensEstimatorVersion = 'utf16-code-units-div-4-v1' | 'script-weighted-v1' | null;
@@ -1,2 +1,2 @@
1
1
 
2
- export type TrainingCostEstimateOneOfTwosevenInputsValidationAnyOfReportAnyOfTokensEstimatorVersion = 'utf16-code-units-div-4-v1' | null;
2
+ export type TrainingCostEstimateOneOfTwosevenInputsValidationAnyOfReportAnyOfTokensEstimatorVersion = 'utf16-code-units-div-4-v1' | 'script-weighted-v1' | null;
@@ -1,2 +1,2 @@
1
1
 
2
- export type TrainingRunInputsAnyOfTrainingReportTokensEstimatorVersion = 'utf16-code-units-div-4-v1' | null;
2
+ export type TrainingRunInputsAnyOfTrainingReportTokensEstimatorVersion = 'utf16-code-units-div-4-v1' | 'script-weighted-v1' | null;
@@ -1,2 +1,2 @@
1
1
 
2
- export type TrainingRunInputsAnyOfValidationAnyOfReportTokensEstimatorVersion = 'utf16-code-units-div-4-v1' | null;
2
+ export type TrainingRunInputsAnyOfValidationAnyOfReportTokensEstimatorVersion = 'utf16-code-units-div-4-v1' | 'script-weighted-v1' | null;
@@ -1,2 +1,2 @@
1
1
 
2
- export type TrainingRunQuoteInputsTrainingReportAnyOfTokensEstimatorVersion = 'utf16-code-units-div-4-v1' | null;
2
+ export type TrainingRunQuoteInputsTrainingReportAnyOfTokensEstimatorVersion = 'utf16-code-units-div-4-v1' | 'script-weighted-v1' | null;
@@ -1,2 +1,2 @@
1
1
 
2
- export type TrainingRunQuoteInputsValidationAnyOfReportAnyOfTokensEstimatorVersion = 'utf16-code-units-div-4-v1' | null;
2
+ export type TrainingRunQuoteInputsValidationAnyOfReportAnyOfTokensEstimatorVersion = 'utf16-code-units-div-4-v1' | 'script-weighted-v1' | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toloka-platform/sdk",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "private": false,
5
5
  "description": "Build, inspect, and operate Toloka pipeline projects as TypeScript source. The public API may change between minor versions before 1.0.",
6
6
  "license": "Apache-2.0",
@@ -77,6 +77,6 @@
77
77
  "bun": ">=1.4.0"
78
78
  },
79
79
  "tolokaBuild": {
80
- "commit": "b2ff2ccd6ae9cffcac3ebe9f19ff2feab4adfe34"
80
+ "commit": "63680479b4e4905b946650ebec6070af910e2340"
81
81
  }
82
82
  }
@@ -11,8 +11,8 @@
11
11
  "testing",
12
12
  "checks"
13
13
  ],
14
- "version": "0.12.1",
15
- "digest": "7e6b79b9b85fbfc86cf98f33ebd30fdb4617707d22f7c24440bee2fedecb5f71",
14
+ "version": "0.13.0",
15
+ "digest": "1595dd10deec49f9f940445f26fe0dc0ed1383ffccb33e42d1ad05d282e71a5c",
16
16
  "files": [
17
17
  "SKILL.md",
18
18
  "references/human-work.md",
@@ -33,7 +33,7 @@
33
33
  "bug",
34
34
  "report"
35
35
  ],
36
- "version": "0.12.1",
36
+ "version": "0.13.0",
37
37
  "digest": "70f0bd2c80b32f87896aeb27c363b8a2d37f40e22424f57fe1aad142e125ad67",
38
38
  "files": [
39
39
  "SKILL.md",
@@ -50,7 +50,7 @@
50
50
  "getting-started",
51
51
  "agent"
52
52
  ],
53
- "version": "0.12.1",
53
+ "version": "0.13.0",
54
54
  "digest": "2278adeb46a792356579395fcf73c42322cb23bcd0c61e20856ccabdad6762d1",
55
55
  "files": [
56
56
  "SKILL.md"
@@ -67,8 +67,8 @@
67
67
  "sft",
68
68
  "models"
69
69
  ],
70
- "version": "0.12.1",
71
- "digest": "a36f9cca96878b0a1da1e0ea75df1d72abae58cc93d87251e5a3d57e95759841",
70
+ "version": "0.13.0",
71
+ "digest": "3ce10dee5d3c283d8b5fdea15134a58fc738c7af2c1bb19eb5a0bf70ea0bca13",
72
72
  "files": [
73
73
  "SKILL.md"
74
74
  ]
@@ -84,8 +84,8 @@
84
84
  "prompt",
85
85
  "models"
86
86
  ],
87
- "version": "0.12.1",
88
- "digest": "d44fe5dde40fb4f3287834b089896a63657c4a238ba37d11825876393eeb68d5",
87
+ "version": "0.13.0",
88
+ "digest": "be8bce8d9cf7241ccb60d2b2a9b7cc07d7755a76e8ff8ec1b0847c49efbb3469",
89
89
  "files": [
90
90
  "SKILL.md"
91
91
  ]
@@ -35,7 +35,7 @@ Run `toloka --help` and `toloka <command> --help` for the exact commands and opt
35
35
  - source reconciliation: `init`, `import`, `check`, `validate`, `plan`, `apply`, `status`, `secret set`;
36
36
  - catalogs: `audience specialization list`, `generation-model list`, `ui components`;
37
37
  - data and runs: `dataset` (`list`, `create`, `fields`, `fields add`, `columns`, `load`, `upload`, `split`, `slice`), `pipeline` (`list`, `run`, `status`, `runs`, `cost`, `results`, `cancel`);
38
- - models and training: `base-model`, `model` (including `model version download`), `training`;
38
+ - models and training: `base-model`, `model` (including `model version download`), `training`, `batch-inference` (`run`, `list`, `status`, `confirm`, `resume`, `cancel`);
39
39
  - skills and reports: `skill` (`list`, `search`, `install`), `report`.
40
40
 
41
41
  `toloka audience specialization list` prints the global specialization catalog: `ID`, `NAME`, and `EXPERTS` columns (`--json` for the array). Run it before setting `audience.specializations` on a node, pick entries by name, and copy `ID` into `qualificationId` and `NAME` into `value`; never invent a `qualificationId`. `EXPERTS` counts ID-verified experts currently eligible for tasks; a `0` means the id is valid but nobody currently qualifies, so prefer another specialization or widen the audience.
@@ -58,6 +58,10 @@ Hyperparameters are optional flags on `training create` and `training update`; t
58
58
 
59
59
  Use `training cost` to validate inputs and show the maximum charge before `training run`. A blocked estimate exits 1 and lists the issues on stderr instead of printing the estimate; fix them and recalculate. `training run` accepts that ready estimate JSON through `--estimate-file`; without it, the command calculates a fresh ready estimate itself before creating the run. `--version-name` defaults to the Training name; pass it when a Model Version with that name already exists. Use `training status`, `training logs`, `training metrics`, `training resume`, and `training cancel` with the returned Training Run ID. `training metrics` lists each metric's latest value while the run is still training; `--key` prints one metric's point history instead. `training cancel` before training starts is free; on a run that is already training it stops the GPU job, and the run is charged only for the GPU seconds used until then and produces no Model Version.
60
60
 
61
+ ## Answer dataset rows with a model
62
+
63
+ `toloka batch-inference run --dataset <id> (--base-model <id> | --model-version <id>) (--output-field <name> | --output-dataset <name>) --max-output-tokens <n>` sends each selected row's `messages` to a qwen3-4b or qwen3-8b Base Model, or a Model Version trained from one, and writes one answer per row into a text column or a new dataset. An existing `--output-field` column must allow strings; one whose schema allows none is refused with "does not accept text", so pick or create a text column. `--filter field=value`, `--slice <id>` and `--parts <names>` (with `--split-column` when the dataset has several) narrow the rows; a slice answers the prompts it froze. `run` waits for the quote and prints the rows and the maximum charge: show them to the user and confirm only with their approval, through `--yes` on `run` or `toloka batch-inference confirm <run-id>` within 24 hours. Follow a run with `status --wait`. A `blocked` run names its reason: after `funds` or `payment`, `resume` continues it once the user adds funds; `billing_review` waits for support to reconcile the charge, and `resume` does not apply to it. `cancel` stops a run and charges the GPU time used, and `list` shows the project's runs. A scoped token needs `inference:deploy` (the `deploy` preset) to run, confirm, resume or cancel. `toloka batch-inference <command> --help` lists every flag.
64
+
61
65
  ## Check locally and validate against the platform
62
66
 
63
67
  Run the complete local gate first, then validate every bound pipeline remotely:
@@ -13,7 +13,7 @@ For first-time setup details, read `https://platform.toloka.ai/agents/fine-tunin
13
13
 
14
14
  ## Domain model
15
15
 
16
- - **SFT** adapts model weights from representative chat examples. Each training row must follow the platform chat contract and end with the assistant response the model should learn to produce.
16
+ - **SFT** adapts model weights from representative chat examples. Each training row must follow the platform chat contract and end with the assistant response the model should learn to produce. Rows with tool calls also need `tools` declaring every function they call. Each call's `arguments` must be a string holding a JSON object (it is not checked against the function's `parameters`), call ids must be unique within a turn, and the `tool` replies must answer every call before the next turn. Cost estimation rejects rows that break these rules and names the first few in its error.
17
17
  - A **Training** is an editable project-owned draft. A **Training Run** is one immutable, billable execution of a frozen draft and the rows of its slice.
18
18
  - A run can start from a catalog **Base Model** or an exact existing **Model Version**. An explicit Model Version is the source; do not also select a Base Model.
19
19
  - A completed run publishes a durable Model Version. It does not prove deployment or inference readiness.
@@ -163,6 +163,7 @@ Control and billing rules:
163
163
  - `payment_window_expired` is final: the run is `failed`, cannot resume, and was not charged, even though `billingStatus` remains `payment_required`. A replacement run needs funds and new cost approval.
164
164
  - Cancel only on explicit request, before output checks begin. Before training starts, cancellation is free. During training, it stops the GPU job and charges for GPU seconds used, with no Model Version. A startup cancellation may remain `stopping` until the job stops; wait rather than retrying cancel.
165
165
  - `provider_failed` and `provider_timeout` are platform failures: no charge, full hold returned. Reported GPU usage remains visible.
166
+ - A `failed` or `canceled` run frees its estimate: the same estimate file can start one new run at the same `maximumCharge` until the estimate expires. Retry only an error with `retryable: true` (network, storage, or GPU capacity), and only after the user agrees.
166
167
 
167
168
  Do not duplicate a slow run. Progress `queued` or `pending` means it is waiting for GPUs; training starts automatically. Training may also exceed the estimated duration. The charge stays capped at the approved `maximumCharge`; successful runs still publish a Model Version.
168
169
 
@@ -78,7 +78,7 @@ To train on a subset or reuse rows across Trainings, freeze a slice once every u
78
78
  toloka dataset slice create <dataset-name> --name "<slice-name>" --json
79
79
  ```
80
80
 
81
- Check that the examples demonstrate the desired behavior under the prompt: dynamic input in user messages, target output in the final assistant message, representative edge cases, and no prompt or answer leakage across validation.
81
+ Check that the examples demonstrate the desired behavior under the prompt: dynamic input in user messages, target output in the final assistant message, representative edge cases, and no prompt or answer leakage across validation. Rows with tool calls also need `tools` declaring every function they call. Each call's `arguments` must be a string holding a JSON object (it is not checked against the function's `parameters`), call ids must be unique within a turn, and the `tool` replies must answer every call before the next turn. Cost estimation rejects rows that break these rules and names the first few in its error.
82
82
 
83
83
  ### 3. Preserve the prompt and choose the source
84
84
 
@@ -170,6 +170,7 @@ Control and billing rules:
170
170
  - `payment_window_expired` is final: the run is `failed`, cannot resume, and was not charged, even though `billingStatus` remains `payment_required`. A replacement run needs funds and new cost approval.
171
171
  - Cancel only on explicit request, before output checks begin. Before training starts, cancellation is free. During training, it stops the GPU job and charges for GPU seconds used, with no Model Version. A startup cancellation may remain `stopping` until the job stops; wait rather than retrying cancel.
172
172
  - `provider_failed` and `provider_timeout` are platform failures: no charge, full hold returned. Reported GPU usage remains visible.
173
+ - A `failed` or `canceled` run frees its estimate: the same estimate file can start one new run at the same `maximumCharge` until the estimate expires. Retry only an error with `retryable: true` (network, storage, or GPU capacity), and only after the user agrees.
173
174
 
174
175
  Do not duplicate a slow run. Progress `queued` or `pending` means it is waiting for GPUs; training starts automatically. Training may also exceed the estimated duration. The charge stays capped at the approved `maximumCharge`; successful runs still publish a Model Version.
175
176
 
@@ -182,4 +183,4 @@ toloka model versions <model-id> --json
182
183
  toloka model version download <model-version-id> --out <absolute-output-directory>
183
184
  ```
184
185
 
185
- The downloaded folder contains full model weights (`config.json` and `model-*.safetensors`) and tokenizer files, including supported text sidecars such as `merges.txt` and `chat_template.jinja`. Keep the files together. The learned prompt is represented by `<|gist_…|>` tokens that prefix requests in place of the original prompt. Verify serving separately with a compatible runtime; a successful download alone does not establish inference readiness.
186
+ The downloaded folder contains full model weights (`config.json` and `model-*.safetensors`) and tokenizer files, including supported text sidecars such as `merges.txt` and `chat_template.jinja`. Keep the files together. The learned prompt is represented by the special tokens `<|gist_0|>`, `<|gist_1|>`, and so on. A request must match training: the gist tokens first as plain text, then the conversation without the final assistant turn rendered by the tokenizer's chat template with `add_generation_prompt=True` and `enable_thinking=False`, without the original prompt. Send that string to a completions endpoint, because a chat endpoint wraps it in message markers; a system message holding only the gist tokens is the closest chat-only fallback and must be checked on validation rows. Verify serving separately with a compatible runtime; a successful download alone does not establish inference readiness.
@@ -108,6 +108,14 @@ const COMMAND_GROUPS: Readonly<Record<string, CommandGroup>> = {
108
108
  metrics: true,
109
109
  logs: true,
110
110
  },
111
+ "batch-inference": {
112
+ run: true,
113
+ list: true,
114
+ status: true,
115
+ confirm: true,
116
+ resume: true,
117
+ cancel: true,
118
+ },
111
119
  "base-model": { list: true, get: true },
112
120
  "generation-model": { list: true },
113
121
  model: {
@@ -0,0 +1,267 @@
1
+ import { randomUUID } from "node:crypto";
2
+
3
+ import type { BatchInferenceRun, PotatoClient } from "../client";
4
+ import type { BaseModelId, CreateBatchInferenceRunBody } from "../../openapi/gen/models";
5
+ import { assertCli } from "./cli-error";
6
+ import { resolveFieldValueFilters } from "./filters";
7
+ import { resolveModelVersion } from "./models";
8
+ import { resolveSplitParts } from "./splits";
9
+ import { formatTable, type TableIo as BatchInferenceIo, writeOutput } from "./table";
10
+
11
+ type BatchInferenceApi = Pick<PotatoClient, "batchInference">;
12
+ type BatchInferenceStartApi = Pick<
13
+ PotatoClient,
14
+ "batchInference" | "datasets" | "models" | "baseModels"
15
+ >;
16
+
17
+ const QUOTE_WAIT_MS = 10 * 60 * 1_000;
18
+ const SETTLED_STATUSES: ReadonlySet<BatchInferenceRun["status"]> = new Set([
19
+ "awaiting_confirmation",
20
+ "blocked",
21
+ "completed",
22
+ "failed",
23
+ "canceled",
24
+ ]);
25
+
26
+ const sleep = (ms: number) =>
27
+ new Promise<void>((resolve) => {
28
+ setTimeout(resolve, ms);
29
+ });
30
+
31
+ export const formatBatchInferenceRun = (run: BatchInferenceRun): string =>
32
+ formatTable([
33
+ ["ID", run.id],
34
+ ["Status", run.status],
35
+ ["Dataset", run.datasetId],
36
+ ["Model", run.model.type === "base_model" ? run.model.baseModelId : run.model.modelVersionId],
37
+ [
38
+ "Output",
39
+ run.output.type === "field"
40
+ ? `field ${run.output.fieldId} on dataset ${run.output.datasetId}`
41
+ : `new dataset ${run.output.datasetId}`,
42
+ ],
43
+ ...(run.quote
44
+ ? [
45
+ ["Rows", String(run.quote.requests)],
46
+ ["Skipped rows", String(run.quote.skippedRows)],
47
+ ["Maximum charge", `$${run.quote.maximumCharge}`],
48
+ ...(run.quote.confirmBefore ? [["Confirm before", run.quote.confirmBefore]] : []),
49
+ ]
50
+ : []),
51
+ ...(run.progress?.requests
52
+ ? [["Progress", `${run.progress.requests.done}/${run.progress.requests.total} rows`]]
53
+ : []),
54
+ ...(run.chargedAmount ? [["Charged", `$${run.chargedAmount}`]] : []),
55
+ ...(run.result
56
+ ? [
57
+ ["Written", String(run.result.written)],
58
+ ["Failed", String(run.result.failed)],
59
+ ["Cut at max tokens", String(run.result.truncated)],
60
+ ["Tokens", `${run.result.inputTokens} in, ${run.result.outputTokens} out`],
61
+ ]
62
+ : []),
63
+ ...(run.message ? [["Message", run.message]] : []),
64
+ ]);
65
+
66
+ const waitUntil = async (
67
+ client: BatchInferenceApi,
68
+ batchInferenceRunId: string,
69
+ isReady: (run: BatchInferenceRun) => boolean,
70
+ pollIntervalMs: number,
71
+ timeoutMs: number,
72
+ ): Promise<BatchInferenceRun> => {
73
+ const deadline = Date.now() + timeoutMs;
74
+ for (;;) {
75
+ const run = await client.batchInference.getRun({ batchInferenceRunId });
76
+ if (isReady(run)) return run;
77
+ assertCli(Date.now() < deadline, `Batch Inference Run ${run.id} is still ${run.status}.`, {
78
+ hint: { description: `Check it later with toloka batch-inference status ${run.id}.` },
79
+ });
80
+ await sleep(pollIntervalMs);
81
+ }
82
+ };
83
+
84
+ export type StartBatchInferenceRunInput = {
85
+ projectId: string;
86
+ datasetId: string;
87
+ filter?: string;
88
+ slice?: string;
89
+ parts?: string[];
90
+ splitColumn?: string;
91
+ baseModel?: BaseModelId;
92
+ modelVersion?: string;
93
+ outputField?: string;
94
+ outputDataset?: string;
95
+ maxOutputTokens: number;
96
+ temperature?: number;
97
+ topP?: number;
98
+ stop: string[];
99
+ seed?: number;
100
+ samplesPerRow?: number;
101
+ idempotencyKey?: string;
102
+ yes: boolean;
103
+ json: boolean;
104
+ pollIntervalMs?: number;
105
+ };
106
+
107
+ const resolveItemFilter = async (
108
+ client: BatchInferenceStartApi,
109
+ input: StartBatchInferenceRunInput,
110
+ ): Promise<CreateBatchInferenceRunBody["itemFilter"]> => {
111
+ assertCli(
112
+ input.splitColumn === undefined || input.parts !== undefined,
113
+ "--split-column needs --parts.",
114
+ { hint: { description: "Pass --parts test to answer the rows of the test part." } },
115
+ );
116
+ const itemFilter = {
117
+ ...(input.filter !== undefined &&
118
+ (await resolveFieldValueFilters(
119
+ client,
120
+ { datasetId: input.datasetId, name: input.datasetId, nameIsUnique: false },
121
+ [input.filter],
122
+ ))),
123
+ ...(input.slice !== undefined && { slice: { sliceId: input.slice } }),
124
+ ...(input.parts !== undefined && {
125
+ parts: await resolveSplitParts(client, input.datasetId, {
126
+ splitColumn: input.splitColumn,
127
+ parts: input.parts,
128
+ }),
129
+ }),
130
+ };
131
+ return Object.keys(itemFilter).length > 0 ? itemFilter : undefined;
132
+ };
133
+
134
+ export const startBatchInferenceRun = async (
135
+ client: BatchInferenceStartApi,
136
+ input: StartBatchInferenceRunInput,
137
+ io: BatchInferenceIo,
138
+ ): Promise<void> => {
139
+ assertCli(
140
+ (input.baseModel === undefined) !== (input.modelVersion === undefined),
141
+ "Pass exactly one of --base-model or --model-version.",
142
+ {
143
+ hint: {
144
+ description: "Run toloka base-model list or toloka model versions <model> to pick one.",
145
+ },
146
+ },
147
+ );
148
+ assertCli(
149
+ (input.outputField === undefined) !== (input.outputDataset === undefined),
150
+ "Pass exactly one of --output-field or --output-dataset.",
151
+ {
152
+ hint: {
153
+ description:
154
+ "--output-field writes a column on the dataset; --output-dataset creates a new dataset with the prompts and answers.",
155
+ },
156
+ },
157
+ );
158
+ const itemFilter = await resolveItemFilter(client, input);
159
+ const model: CreateBatchInferenceRunBody["model"] = input.baseModel
160
+ ? { type: "base_model", baseModelId: input.baseModel }
161
+ : {
162
+ type: "model_version",
163
+ modelVersionId: (await resolveModelVersion(client, input.projectId, input.modelVersion!))
164
+ .id,
165
+ };
166
+ const created = await client.batchInference.createRun({
167
+ projectId: input.projectId,
168
+ idempotencyKey: input.idempotencyKey ?? randomUUID(),
169
+ datasetId: input.datasetId,
170
+ ...(itemFilter && { itemFilter }),
171
+ model,
172
+ sampling: {
173
+ maxOutputTokens: input.maxOutputTokens,
174
+ ...(input.temperature !== undefined && { temperature: input.temperature }),
175
+ ...(input.topP !== undefined && { topP: input.topP }),
176
+ ...(input.stop.length > 0 && { stop: input.stop }),
177
+ ...(input.seed !== undefined && { seed: input.seed }),
178
+ ...(input.samplesPerRow !== undefined && { samplesPerRow: input.samplesPerRow }),
179
+ },
180
+ output:
181
+ input.outputField === undefined
182
+ ? { type: "dataset", name: input.outputDataset! }
183
+ : { type: "field", fieldName: input.outputField },
184
+ });
185
+ const quoted = await waitUntil(
186
+ client,
187
+ created.id,
188
+ (run) => run.status !== "preparing",
189
+ input.pollIntervalMs ?? 1_000,
190
+ QUOTE_WAIT_MS,
191
+ );
192
+ assertCli(quoted.status === "awaiting_confirmation", formatBatchInferenceRun(quoted), {
193
+ hint: { description: "Fix the selection or the model, then start a new run." },
194
+ });
195
+ if (!input.yes) {
196
+ writeOutput(
197
+ io,
198
+ input.json,
199
+ quoted,
200
+ `${formatBatchInferenceRun(quoted)}\n\nConfirm the maximum charge with: toloka batch-inference confirm ${quoted.id}`,
201
+ );
202
+ return;
203
+ }
204
+ const confirmed = await client.batchInference.confirmRun({ batchInferenceRunId: quoted.id });
205
+ writeOutput(io, input.json, confirmed, formatBatchInferenceRun(confirmed));
206
+ };
207
+
208
+ export const listBatchInferenceRuns = async (
209
+ client: BatchInferenceApi,
210
+ input: { projectId: string; json: boolean },
211
+ io: BatchInferenceIo,
212
+ ): Promise<void> => {
213
+ const page = await client.batchInference.listRunsPage({
214
+ projectId: input.projectId,
215
+ limit: 100,
216
+ offset: 0,
217
+ });
218
+ writeOutput(
219
+ io,
220
+ input.json,
221
+ page.batchInferenceRuns,
222
+ page.batchInferenceRuns.length === 0
223
+ ? "No Batch Inference Runs found."
224
+ : formatTable([
225
+ ["ID", "STATUS", "DATASET", "MAXIMUM CHARGE", "CHARGED"],
226
+ ...page.batchInferenceRuns.map((run) => [
227
+ run.id,
228
+ run.status,
229
+ run.datasetId,
230
+ run.quote ? `$${run.quote.maximumCharge}` : "-",
231
+ run.chargedAmount ? `$${run.chargedAmount}` : "-",
232
+ ]),
233
+ ]),
234
+ );
235
+ };
236
+
237
+ export const getBatchInferenceRun = async (
238
+ client: BatchInferenceApi,
239
+ input: { batchInferenceRunId: string; wait: boolean; json: boolean; pollIntervalMs?: number },
240
+ io: BatchInferenceIo,
241
+ ): Promise<void> => {
242
+ const run = input.wait
243
+ ? await waitUntil(
244
+ client,
245
+ input.batchInferenceRunId,
246
+ (candidate) => SETTLED_STATUSES.has(candidate.status),
247
+ input.pollIntervalMs ?? 5_000,
248
+ Number.POSITIVE_INFINITY,
249
+ )
250
+ : await client.batchInference.getRun({ batchInferenceRunId: input.batchInferenceRunId });
251
+ writeOutput(io, input.json, run, formatBatchInferenceRun(run));
252
+ };
253
+
254
+ export const changeBatchInferenceRun = async (
255
+ client: BatchInferenceApi,
256
+ input: { batchInferenceRunId: string; action: "confirm" | "cancel" | "resume"; json: boolean },
257
+ io: BatchInferenceIo,
258
+ ): Promise<void> => {
259
+ const request = { batchInferenceRunId: input.batchInferenceRunId };
260
+ const run =
261
+ input.action === "confirm"
262
+ ? await client.batchInference.confirmRun(request)
263
+ : input.action === "cancel"
264
+ ? await client.batchInference.cancelRun(request)
265
+ : await client.batchInference.resumeRun(request);
266
+ writeOutput(io, input.json, run, formatBatchInferenceRun(run));
267
+ };