@toloka-platform/sdk 0.1.0-preview.5 → 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.
- package/dist/cli/toloka.js +121 -120
- package/dist/cli/toloka.js.jsc +0 -0
- package/dist/cli/toloka.js.jsc.sha256 +1 -1
- package/dist/cli/toloka.js.sha256 +1 -1
- package/docs/cli.md +26 -1
- package/docs/datasets.md +8 -9
- package/docs/limitations.md +5 -8
- package/docs/troubleshooting.md +0 -11
- package/openapi/gen/api.ts +779 -895
- package/openapi/gen/models/baseModel.ts +9 -0
- package/openapi/gen/models/baseModelId.ts +2 -0
- package/openapi/gen/models/baseModelIdProperty.ts +2 -0
- package/openapi/gen/models/createProjectModelBody.ts +8 -0
- package/openapi/gen/models/createProjectModelBodyDescription.ts +2 -0
- package/openapi/gen/models/generationNodeSettingsAudienceAndPricingOneOfOneone.ts +1 -0
- package/openapi/gen/models/index.ts +16 -0
- package/openapi/gen/models/listBaseModels200.ts +5 -0
- package/openapi/gen/models/listModelVersions200.ts +7 -0
- package/openapi/gen/models/listModelVersionsParams.ts +5 -0
- package/openapi/gen/models/listProjectModels200.ts +7 -0
- package/openapi/gen/models/listProjectModelsParams.ts +5 -0
- package/openapi/gen/models/model.ts +16 -0
- package/openapi/gen/models/modelArchivedAt.ts +2 -0
- package/openapi/gen/models/modelDescription.ts +2 -0
- package/openapi/gen/models/modelId.ts +2 -0
- package/openapi/gen/models/modelVersion.ts +9 -0
- package/openapi/gen/models/modelVersionId.ts +2 -0
- package/openapi/gen/models/pipelineGraphSnapshotGraphNodesItemOneOfThreeoneSettingsAudienceAndPricingOneOfOneone.ts +1 -0
- package/openapi/gen/models/validatePipelineGraphBodyGraphNodesItemOneOfThreeoneSettingsAudienceAndPricingOneOfOneone.ts +1 -0
- package/package.json +1 -1
- package/skills/catalog.json +4 -4
- package/skills/toloka-build/SKILL.md +1 -1
- package/skills/toloka-build/references/workflow-and-cli.md +12 -1
- package/skills/toloka-report-issue/references/report-template.md +1 -1
- package/src/cli/data.ts +148 -25
- package/src/cli/models.ts +188 -0
- package/src/cli/program.ts +99 -1
- package/src/client.ts +109 -35
- package/src/errors.ts +25 -10
- package/src/transport.ts +16 -13
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { assert } from "es-toolkit";
|
|
2
|
+
|
|
3
|
+
import type { BaseModel, BaseModelId, Model, ModelVersion, PotatoClient } from "../client";
|
|
4
|
+
|
|
5
|
+
type ModelApi = Pick<PotatoClient, "baseModels" | "models">;
|
|
6
|
+
type ModelIo = { readonly stdout: (text: string) => void };
|
|
7
|
+
type TableRow = readonly string[];
|
|
8
|
+
|
|
9
|
+
const BASE_MODEL_IDS = [
|
|
10
|
+
"qwen3-4b",
|
|
11
|
+
"qwen3-8b",
|
|
12
|
+
"qwen3-32b",
|
|
13
|
+
"qwen3-235b",
|
|
14
|
+
] satisfies readonly BaseModelId[];
|
|
15
|
+
|
|
16
|
+
const formatTable = (rows: readonly TableRow[]): string => {
|
|
17
|
+
const widths = rows.reduce<number[]>(
|
|
18
|
+
(current, row) => row.map((cell, index) => Math.max(current[index] ?? 0, cell.length)),
|
|
19
|
+
[],
|
|
20
|
+
);
|
|
21
|
+
return rows
|
|
22
|
+
.map((row) =>
|
|
23
|
+
row
|
|
24
|
+
.map((cell, index) => cell.padEnd(widths[index] ?? cell.length))
|
|
25
|
+
.join(" ")
|
|
26
|
+
.trimEnd(),
|
|
27
|
+
)
|
|
28
|
+
.join("\n");
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const writeOutput = (io: ModelIo, json: boolean, value: unknown, formatted: string): void => {
|
|
32
|
+
io.stdout(json ? JSON.stringify(value, null, 2) : formatted);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const formatBaseModel = (model: BaseModel): string =>
|
|
36
|
+
formatTable([
|
|
37
|
+
["ID", model.id],
|
|
38
|
+
["Name", model.displayName],
|
|
39
|
+
["Provider", model.provider],
|
|
40
|
+
["Upstream model", model.upstreamModel],
|
|
41
|
+
["Upstream revision", model.upstreamRevision],
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
const formatModel = (model: Model): string =>
|
|
45
|
+
formatTable([
|
|
46
|
+
["ID", model.id],
|
|
47
|
+
["Project", model.projectId],
|
|
48
|
+
["Name", model.name],
|
|
49
|
+
["Base model", model.baseModelId],
|
|
50
|
+
["Description", model.description ?? "-"],
|
|
51
|
+
["Archived at", model.archivedAt ?? "-"],
|
|
52
|
+
["Created at", model.createdAt],
|
|
53
|
+
["Updated at", model.updatedAt],
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
export const parseBaseModelId = (value: string): BaseModelId => {
|
|
57
|
+
const modelId = BASE_MODEL_IDS.find((candidate) => candidate === value);
|
|
58
|
+
assert(modelId, `Unknown base model ${value}.`);
|
|
59
|
+
return modelId;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const resolveModel = async (
|
|
63
|
+
client: ModelApi,
|
|
64
|
+
projectId: string,
|
|
65
|
+
nameOrId: string,
|
|
66
|
+
): Promise<Model> => {
|
|
67
|
+
if (nameOrId.startsWith("mdl.")) return client.models.get({ projectId, modelId: nameOrId });
|
|
68
|
+
const matches: Model[] = [];
|
|
69
|
+
for await (const model of client.models.listAll({ projectId, limit: 100 })) {
|
|
70
|
+
if (model.name === nameOrId) matches.push(model);
|
|
71
|
+
}
|
|
72
|
+
assert(matches.length === 1, `Model ${nameOrId} was not found or is ambiguous.`);
|
|
73
|
+
return matches[0]!;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const listBaseModels = async (
|
|
77
|
+
client: ModelApi,
|
|
78
|
+
input: { json: boolean },
|
|
79
|
+
io: ModelIo,
|
|
80
|
+
): Promise<void> => {
|
|
81
|
+
const models = await client.baseModels.list();
|
|
82
|
+
writeOutput(
|
|
83
|
+
io,
|
|
84
|
+
input.json,
|
|
85
|
+
models,
|
|
86
|
+
models.length === 0
|
|
87
|
+
? "No base models found."
|
|
88
|
+
: formatTable([
|
|
89
|
+
["ID", "NAME", "PROVIDER", "UPSTREAM MODEL"],
|
|
90
|
+
...models.map((model) => [
|
|
91
|
+
model.id,
|
|
92
|
+
model.displayName,
|
|
93
|
+
model.provider,
|
|
94
|
+
model.upstreamModel,
|
|
95
|
+
]),
|
|
96
|
+
]),
|
|
97
|
+
);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const getBaseModel = async (
|
|
101
|
+
client: ModelApi,
|
|
102
|
+
input: { id: BaseModelId; json: boolean },
|
|
103
|
+
io: ModelIo,
|
|
104
|
+
): Promise<void> => {
|
|
105
|
+
const model = await client.baseModels.get({ id: input.id });
|
|
106
|
+
writeOutput(io, input.json, model, formatBaseModel(model));
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export const listModels = async (
|
|
110
|
+
client: ModelApi,
|
|
111
|
+
input: { projectId: string; json: boolean },
|
|
112
|
+
io: ModelIo,
|
|
113
|
+
): Promise<void> => {
|
|
114
|
+
const page = await client.models.listPage({ projectId: input.projectId, limit: 100, offset: 0 });
|
|
115
|
+
writeOutput(
|
|
116
|
+
io,
|
|
117
|
+
input.json,
|
|
118
|
+
page.models,
|
|
119
|
+
page.models.length === 0
|
|
120
|
+
? "No models found."
|
|
121
|
+
: formatTable([
|
|
122
|
+
["ID", "NAME", "BASE MODEL"],
|
|
123
|
+
...page.models.map((model) => [model.id, model.name, model.baseModelId]),
|
|
124
|
+
]),
|
|
125
|
+
);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
export const getModel = async (
|
|
129
|
+
client: ModelApi,
|
|
130
|
+
input: { projectId: string; nameOrId: string; json: boolean },
|
|
131
|
+
io: ModelIo,
|
|
132
|
+
): Promise<void> => {
|
|
133
|
+
const model = await resolveModel(client, input.projectId, input.nameOrId);
|
|
134
|
+
writeOutput(io, input.json, model, formatModel(model));
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export const listModelVersions = async (
|
|
138
|
+
client: ModelApi,
|
|
139
|
+
input: { projectId: string; nameOrId: string; json: boolean },
|
|
140
|
+
io: ModelIo,
|
|
141
|
+
): Promise<void> => {
|
|
142
|
+
const model = await resolveModel(client, input.projectId, input.nameOrId);
|
|
143
|
+
const versions: ModelVersion[] = [];
|
|
144
|
+
for await (const version of client.models.listAllVersions({
|
|
145
|
+
projectId: input.projectId,
|
|
146
|
+
modelId: model.id,
|
|
147
|
+
limit: 100,
|
|
148
|
+
})) {
|
|
149
|
+
versions.push(version);
|
|
150
|
+
}
|
|
151
|
+
writeOutput(
|
|
152
|
+
io,
|
|
153
|
+
input.json,
|
|
154
|
+
versions,
|
|
155
|
+
versions.length === 0
|
|
156
|
+
? "No Model Versions found."
|
|
157
|
+
: formatTable([
|
|
158
|
+
["VERSION", "ID", "CREATED AT"],
|
|
159
|
+
...versions.map((version) => [version.version, version.id, version.createdAt]),
|
|
160
|
+
]),
|
|
161
|
+
);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export const createModel = async (
|
|
165
|
+
client: ModelApi,
|
|
166
|
+
input: {
|
|
167
|
+
projectId: string;
|
|
168
|
+
name: string;
|
|
169
|
+
description?: string;
|
|
170
|
+
baseModelId: BaseModelId;
|
|
171
|
+
json: boolean;
|
|
172
|
+
},
|
|
173
|
+
io: ModelIo,
|
|
174
|
+
): Promise<void> => {
|
|
175
|
+
const { json, ...body } = input;
|
|
176
|
+
const model = await client.models.create(body);
|
|
177
|
+
writeOutput(io, json, model, formatModel(model));
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
export const archiveModel = async (
|
|
181
|
+
client: ModelApi,
|
|
182
|
+
input: { projectId: string; nameOrId: string; json: boolean },
|
|
183
|
+
io: ModelIo,
|
|
184
|
+
): Promise<void> => {
|
|
185
|
+
const model = await resolveModel(client, input.projectId, input.nameOrId);
|
|
186
|
+
const archived = await client.models.archive({ projectId: input.projectId, modelId: model.id });
|
|
187
|
+
writeOutput(io, input.json, archived, `Archived Model ${archived.id}.`);
|
|
188
|
+
};
|
package/src/cli/program.ts
CHANGED
|
@@ -33,6 +33,16 @@ import {
|
|
|
33
33
|
projectStatus,
|
|
34
34
|
validateProject,
|
|
35
35
|
} from "./project";
|
|
36
|
+
import {
|
|
37
|
+
archiveModel,
|
|
38
|
+
createModel,
|
|
39
|
+
getBaseModel,
|
|
40
|
+
getModel,
|
|
41
|
+
listBaseModels,
|
|
42
|
+
listModels,
|
|
43
|
+
listModelVersions,
|
|
44
|
+
parseBaseModelId,
|
|
45
|
+
} from "./models";
|
|
36
46
|
import {
|
|
37
47
|
MISSING_PROJECT_ID_MESSAGE,
|
|
38
48
|
addProject,
|
|
@@ -533,6 +543,94 @@ export function createProgram(context: ProgramContext): CreatedProgram {
|
|
|
533
543
|
}
|
|
534
544
|
});
|
|
535
545
|
|
|
546
|
+
const baseModel = program
|
|
547
|
+
.command("base-model")
|
|
548
|
+
.description("inspect the global base model catalog");
|
|
549
|
+
baseModel
|
|
550
|
+
.command("list")
|
|
551
|
+
.option("--json", "print JSON", false)
|
|
552
|
+
.description("list base models")
|
|
553
|
+
.action(async (options: { json: boolean }) => {
|
|
554
|
+
const { client } = await resolveContext(globals(), context);
|
|
555
|
+
await listBaseModels(client, { json: options.json }, context.io);
|
|
556
|
+
});
|
|
557
|
+
baseModel
|
|
558
|
+
.command("get")
|
|
559
|
+
.argument("<id>", "base model ID")
|
|
560
|
+
.option("--json", "print JSON", false)
|
|
561
|
+
.description("show one base model")
|
|
562
|
+
.action(async (id: string, options: { json: boolean }) => {
|
|
563
|
+
const { client } = await resolveContext(globals(), context);
|
|
564
|
+
await getBaseModel(client, { id: parseBaseModelId(id), json: options.json }, context.io);
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
const model = program
|
|
568
|
+
.command("model")
|
|
569
|
+
.description("manage project Models and immutable versions");
|
|
570
|
+
model
|
|
571
|
+
.command("list")
|
|
572
|
+
.option("--json", "print JSON", false)
|
|
573
|
+
.description("list Models owned by the selected project")
|
|
574
|
+
.action(async (options: { json: boolean }) => {
|
|
575
|
+
const { client, projectId } = await resolveContext(globals(), context);
|
|
576
|
+
assert(projectId, MISSING_PROJECT_ID_MESSAGE);
|
|
577
|
+
await listModels(client, { projectId, json: options.json }, context.io);
|
|
578
|
+
});
|
|
579
|
+
model
|
|
580
|
+
.command("get")
|
|
581
|
+
.argument("<name-or-id>", "project Model name or ID")
|
|
582
|
+
.option("--json", "print JSON", false)
|
|
583
|
+
.description("show one project Model")
|
|
584
|
+
.action(async (nameOrId: string, options: { json: boolean }) => {
|
|
585
|
+
const { client, projectId } = await resolveContext(globals(), context);
|
|
586
|
+
assert(projectId, MISSING_PROJECT_ID_MESSAGE);
|
|
587
|
+
await getModel(client, { projectId, nameOrId, json: options.json }, context.io);
|
|
588
|
+
});
|
|
589
|
+
model
|
|
590
|
+
.command("versions")
|
|
591
|
+
.argument("<name-or-id>", "project Model name or ID")
|
|
592
|
+
.option("--json", "print JSON", false)
|
|
593
|
+
.description("list immutable versions of a model")
|
|
594
|
+
.action(async (nameOrId: string, options: { json: boolean }) => {
|
|
595
|
+
const { client, projectId } = await resolveContext(globals(), context);
|
|
596
|
+
assert(projectId, MISSING_PROJECT_ID_MESSAGE);
|
|
597
|
+
await listModelVersions(client, { projectId, nameOrId, json: options.json }, context.io);
|
|
598
|
+
});
|
|
599
|
+
model
|
|
600
|
+
.command("create")
|
|
601
|
+
.argument("<name>", "new Model name")
|
|
602
|
+
.requiredOption("--base <id>", "base model ID")
|
|
603
|
+
.option("--description <text>", "Model description")
|
|
604
|
+
.option("--json", "print JSON", false)
|
|
605
|
+
.description("create project Model metadata without a Model Version")
|
|
606
|
+
.action(
|
|
607
|
+
async (name: string, options: { base: string; description?: string; json: boolean }) => {
|
|
608
|
+
const { client, projectId } = await resolveContext(globals(), context);
|
|
609
|
+
assert(projectId, MISSING_PROJECT_ID_MESSAGE);
|
|
610
|
+
await createModel(
|
|
611
|
+
client,
|
|
612
|
+
{
|
|
613
|
+
projectId,
|
|
614
|
+
name,
|
|
615
|
+
description: options.description,
|
|
616
|
+
baseModelId: parseBaseModelId(options.base),
|
|
617
|
+
json: options.json,
|
|
618
|
+
},
|
|
619
|
+
context.io,
|
|
620
|
+
);
|
|
621
|
+
},
|
|
622
|
+
);
|
|
623
|
+
model
|
|
624
|
+
.command("archive")
|
|
625
|
+
.option("--json", "print JSON", false)
|
|
626
|
+
.argument("<name-or-id>", "project Model name or ID")
|
|
627
|
+
.description("archive a project Model")
|
|
628
|
+
.action(async (nameOrId: string, options: { json: boolean }) => {
|
|
629
|
+
const { client, projectId } = await resolveContext(globals(), context);
|
|
630
|
+
assert(projectId, MISSING_PROJECT_ID_MESSAGE);
|
|
631
|
+
await archiveModel(client, { projectId, nameOrId, json: options.json }, context.io);
|
|
632
|
+
});
|
|
633
|
+
|
|
536
634
|
const dataset = program
|
|
537
635
|
.command("dataset")
|
|
538
636
|
.description("inspect and move dataset catalog and rows");
|
|
@@ -580,7 +678,7 @@ export function createProgram(context: ProgramContext): CreatedProgram {
|
|
|
580
678
|
dataset
|
|
581
679
|
.command("upload")
|
|
582
680
|
.argument("<name>", "dataset name or id")
|
|
583
|
-
.argument("<file>", "
|
|
681
|
+
.argument("<file>", "JSON array, JSONL, or CSV file")
|
|
584
682
|
.description("append rows to a dataset")
|
|
585
683
|
.action(async (name: string, file: string) => {
|
|
586
684
|
const { sourceRoot, client, projectId } = await resolveContext(globals(), context);
|
package/src/client.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
CopyPipelineBody,
|
|
9
9
|
CreateDatasetBody,
|
|
10
10
|
CreateDatasetExportBody,
|
|
11
|
+
CreateProjectModelBody,
|
|
11
12
|
CreateDatasetFieldBodyAnyOf,
|
|
12
13
|
CreateDatasetUploadBody,
|
|
13
14
|
CreatePipelineCheckBody,
|
|
@@ -21,13 +22,17 @@ import type {
|
|
|
21
22
|
ImportPipelineBody,
|
|
22
23
|
InferredField as GeneratedInferredField,
|
|
23
24
|
ListDatasetFieldsParams,
|
|
25
|
+
ListModelVersionsParams,
|
|
24
26
|
ListDatasetItemsParams,
|
|
25
27
|
ListPipelineRunItemsParams,
|
|
26
28
|
ListPipelineRunsParams,
|
|
27
29
|
ListProjectDatasetsParams,
|
|
28
30
|
ListProjectPipelinesParams,
|
|
31
|
+
ListProjectModelsParams,
|
|
29
32
|
ListProjectsParams,
|
|
30
33
|
Pipeline as GeneratedPipeline,
|
|
34
|
+
Model as GeneratedModel,
|
|
35
|
+
ModelVersion as GeneratedModelVersion,
|
|
31
36
|
PatchPipelineNodeBody,
|
|
32
37
|
PipelineGraphSnapshot,
|
|
33
38
|
Project as GeneratedProject,
|
|
@@ -38,6 +43,8 @@ import type {
|
|
|
38
43
|
RunJob as GeneratedRunJob,
|
|
39
44
|
RunSummary as GeneratedRunSummary,
|
|
40
45
|
SetProjectSecretBody,
|
|
46
|
+
BaseModel as GeneratedBaseModel,
|
|
47
|
+
BaseModelId as GeneratedBaseModelId,
|
|
41
48
|
UpdatePipelineBody,
|
|
42
49
|
UpdateProjectBody,
|
|
43
50
|
UploadJob as GeneratedUploadJob,
|
|
@@ -57,6 +64,8 @@ export type DatasetFieldId = Branded<string, "DatasetFieldId">;
|
|
|
57
64
|
export type DatasetId = Branded<string, "DatasetId">;
|
|
58
65
|
export type DatasetItemId = Branded<string, "DatasetItemId">;
|
|
59
66
|
export type ExportId = Branded<string, "ExportId">;
|
|
67
|
+
export type ModelId = Branded<string, "ModelId">;
|
|
68
|
+
export type ModelVersionId = Branded<string, "ModelVersionId">;
|
|
60
69
|
export type PipelineId = Branded<string, "PipelineId">;
|
|
61
70
|
export type ProjectFileId = Branded<string, "ProjectFileId">;
|
|
62
71
|
export type ProjectId = Branded<string, "ProjectId">;
|
|
@@ -76,6 +85,8 @@ type ResourceIdsByProperty = {
|
|
|
76
85
|
exportId: ExportId;
|
|
77
86
|
fieldId: DatasetFieldId;
|
|
78
87
|
fileId: ProjectFileId;
|
|
88
|
+
modelId: ModelId;
|
|
89
|
+
modelVersionId: ModelVersionId;
|
|
79
90
|
goldenDatasetId: DatasetId;
|
|
80
91
|
itemId: RunItemId;
|
|
81
92
|
pipelineId: PipelineId;
|
|
@@ -121,6 +132,10 @@ export type DatasetField = BrandedResource<GeneratedDatasetField, DatasetFieldId
|
|
|
121
132
|
export type DatasetItem = BrandedResource<GeneratedDatasetItem, DatasetItemId>;
|
|
122
133
|
export type ExportJob = BrandedResource<GeneratedExportJob, ExportId>;
|
|
123
134
|
export type InferredField = GeneratedInferredField;
|
|
135
|
+
export type Model = BrandedResource<GeneratedModel, ModelId>;
|
|
136
|
+
export type ModelVersion = BrandedResource<GeneratedModelVersion, ModelVersionId>;
|
|
137
|
+
export type BaseModel = GeneratedBaseModel;
|
|
138
|
+
export type BaseModelId = GeneratedBaseModelId;
|
|
124
139
|
export type Pipeline = BrandedResource<GeneratedPipeline, PipelineId>;
|
|
125
140
|
export type Project = BrandedResource<GeneratedProject, ProjectId>;
|
|
126
141
|
export type ProjectFile = BrandedResource<GeneratedProjectFile, ProjectFileId>;
|
|
@@ -178,6 +193,12 @@ export type WaitForTarget =
|
|
|
178
193
|
const createClientImplementation = (config: ClientConfig) => {
|
|
179
194
|
const requestOptions = createRequestOptions(config.baseUrl, config.apiKey, config.fetch);
|
|
180
195
|
|
|
196
|
+
const emptyJsonRequestOptions = (): RequestInit => {
|
|
197
|
+
const headers = new Headers(requestOptions.headers);
|
|
198
|
+
headers.set("Content-Type", "application/json");
|
|
199
|
+
return { ...requestOptions, headers, body: "{}" };
|
|
200
|
+
};
|
|
201
|
+
|
|
181
202
|
function waitFor(
|
|
182
203
|
target: DatasetUploadWaitTarget,
|
|
183
204
|
options?: WaitForOptions,
|
|
@@ -296,6 +317,56 @@ const createClientImplementation = (config: ClientConfig) => {
|
|
|
296
317
|
wire.copyPipeline(pipelineId, body, requestOptions),
|
|
297
318
|
};
|
|
298
319
|
|
|
320
|
+
const baseModels = {
|
|
321
|
+
list: async () => (await wire.listBaseModels(requestOptions)).baseModels,
|
|
322
|
+
get: ({ id }: { id: BaseModelId }) => wire.getBaseModel(id, requestOptions),
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
const models = {
|
|
326
|
+
listPage: ({ projectId, ...params }: { projectId: ProjectId } & ListProjectModelsParams) =>
|
|
327
|
+
wire.listProjectModels(projectId, params, requestOptions),
|
|
328
|
+
listAll: ({ projectId, ...params }: { projectId: ProjectId } & ListProjectModelsParams) =>
|
|
329
|
+
listAllPages(async (pageOptions) => {
|
|
330
|
+
const page = await wire.listProjectModels(
|
|
331
|
+
projectId,
|
|
332
|
+
{ ...params, ...pageOptions },
|
|
333
|
+
requestOptions,
|
|
334
|
+
);
|
|
335
|
+
return { items: page.models, pagination: page.pagination };
|
|
336
|
+
}, params),
|
|
337
|
+
get: ({ projectId, modelId }: { projectId: ProjectId; modelId: ModelId }) =>
|
|
338
|
+
wire.getProjectModel(projectId, modelId, requestOptions),
|
|
339
|
+
listVersionsPage: ({
|
|
340
|
+
projectId,
|
|
341
|
+
modelId,
|
|
342
|
+
...params
|
|
343
|
+
}: { projectId: ProjectId; modelId: ModelId } & ListModelVersionsParams) =>
|
|
344
|
+
wire.listModelVersions(projectId, modelId, params, requestOptions),
|
|
345
|
+
listAllVersions: ({
|
|
346
|
+
projectId,
|
|
347
|
+
modelId,
|
|
348
|
+
...params
|
|
349
|
+
}: { projectId: ProjectId; modelId: ModelId } & ListModelVersionsParams) =>
|
|
350
|
+
listAllPages(async (pageOptions) => {
|
|
351
|
+
const page = await wire.listModelVersions(
|
|
352
|
+
projectId,
|
|
353
|
+
modelId,
|
|
354
|
+
{ ...params, ...pageOptions },
|
|
355
|
+
requestOptions,
|
|
356
|
+
);
|
|
357
|
+
return { items: page.versions, pagination: page.pagination };
|
|
358
|
+
}, params),
|
|
359
|
+
create: ({ projectId, ...body }: { projectId: ProjectId } & CreateProjectModelBody) =>
|
|
360
|
+
wire.createProjectModel(projectId, body, requestOptions),
|
|
361
|
+
getVersion: ({ modelVersionId }: { modelVersionId: ModelVersionId }) =>
|
|
362
|
+
wire.getModelVersion(modelVersionId, requestOptions),
|
|
363
|
+
archive: ({ projectId, modelId }: { projectId: ProjectId; modelId: ModelId }) => {
|
|
364
|
+
const headers = new Headers(requestOptions.headers);
|
|
365
|
+
headers.set("Content-Type", "application/json");
|
|
366
|
+
return wire.archiveProjectModel(projectId, modelId, { ...requestOptions, headers });
|
|
367
|
+
},
|
|
368
|
+
};
|
|
369
|
+
|
|
299
370
|
const datasets = {
|
|
300
371
|
create: ({ projectId, ...body }: { projectId: ProjectId } & CreateDatasetBody) =>
|
|
301
372
|
wire.createDataset(projectId, body, requestOptions),
|
|
@@ -363,7 +434,9 @@ const createClientImplementation = (config: ClientConfig) => {
|
|
|
363
434
|
startUpload: ({ datasetId, ...body }: { datasetId: DatasetId } & CreateDatasetUploadBody) =>
|
|
364
435
|
wire.createDatasetUpload(datasetId, body, requestOptions),
|
|
365
436
|
finalizeUpload: ({ uploadId }: { uploadId: UploadId }) =>
|
|
366
|
-
wire.finalizeDatasetUpload(uploadId,
|
|
437
|
+
wire.finalizeDatasetUpload(uploadId, emptyJsonRequestOptions()),
|
|
438
|
+
cancelUpload: ({ uploadId }: { uploadId: UploadId }) =>
|
|
439
|
+
wire.cancelDatasetUpload(uploadId, emptyJsonRequestOptions()),
|
|
367
440
|
getUpload: ({ uploadId }: { uploadId: UploadId }) =>
|
|
368
441
|
wire.getDatasetUpload(uploadId, requestOptions),
|
|
369
442
|
startExport: ({ datasetId, ...body }: { datasetId: DatasetId } & CreateDatasetExportBody) =>
|
|
@@ -373,15 +446,8 @@ const createClientImplementation = (config: ClientConfig) => {
|
|
|
373
446
|
};
|
|
374
447
|
|
|
375
448
|
const runs = {
|
|
376
|
-
start: ({ pipelineId }: { pipelineId: PipelineId }) =>
|
|
377
|
-
|
|
378
|
-
headers.set("Content-Type", "application/json");
|
|
379
|
-
return wire.createPipelineRun(pipelineId, {
|
|
380
|
-
...requestOptions,
|
|
381
|
-
headers,
|
|
382
|
-
body: "{}",
|
|
383
|
-
});
|
|
384
|
-
},
|
|
449
|
+
start: ({ pipelineId }: { pipelineId: PipelineId }) =>
|
|
450
|
+
wire.createPipelineRun(pipelineId, emptyJsonRequestOptions()),
|
|
385
451
|
get: ({ runId }: { runId: RunId }) => wire.getPipelineRun(runId, requestOptions),
|
|
386
452
|
cancel: ({ runId }: { runId: RunId }) => wire.cancelPipelineRun(runId, requestOptions),
|
|
387
453
|
listPage: ({ pipelineId, ...params }: { pipelineId: PipelineId } & ListPipelineRunsParams) =>
|
|
@@ -446,6 +512,8 @@ const createClientImplementation = (config: ClientConfig) => {
|
|
|
446
512
|
projects,
|
|
447
513
|
pipelines,
|
|
448
514
|
datasets,
|
|
515
|
+
baseModels,
|
|
516
|
+
models,
|
|
449
517
|
runs,
|
|
450
518
|
secrets,
|
|
451
519
|
files,
|
|
@@ -462,31 +530,37 @@ type PublicOutput<T> = T extends GeneratedCheckJob
|
|
|
462
530
|
? ExportJob
|
|
463
531
|
: T extends GeneratedUploadJob
|
|
464
532
|
? UploadJob
|
|
465
|
-
: T extends
|
|
466
|
-
?
|
|
467
|
-
: T extends
|
|
468
|
-
?
|
|
469
|
-
: T extends
|
|
470
|
-
?
|
|
471
|
-
: T extends
|
|
472
|
-
?
|
|
473
|
-
: T extends
|
|
474
|
-
?
|
|
475
|
-
: T extends
|
|
476
|
-
?
|
|
477
|
-
: T extends
|
|
478
|
-
?
|
|
479
|
-
: T extends
|
|
480
|
-
?
|
|
481
|
-
: T extends
|
|
482
|
-
?
|
|
483
|
-
: T extends
|
|
484
|
-
?
|
|
485
|
-
: T extends
|
|
486
|
-
?
|
|
487
|
-
: T extends
|
|
488
|
-
?
|
|
489
|
-
: T
|
|
533
|
+
: T extends GeneratedModel
|
|
534
|
+
? Model
|
|
535
|
+
: T extends GeneratedModelVersion
|
|
536
|
+
? ModelVersion
|
|
537
|
+
: T extends GeneratedProject
|
|
538
|
+
? Project
|
|
539
|
+
: T extends GeneratedPipeline
|
|
540
|
+
? Pipeline
|
|
541
|
+
: T extends GeneratedDataset
|
|
542
|
+
? Dataset
|
|
543
|
+
: T extends GeneratedDatasetField
|
|
544
|
+
? DatasetField
|
|
545
|
+
: T extends GeneratedDatasetItem
|
|
546
|
+
? DatasetItem
|
|
547
|
+
: T extends GeneratedProjectFile
|
|
548
|
+
? ProjectFile
|
|
549
|
+
: T extends GeneratedRunItem
|
|
550
|
+
? RunItem
|
|
551
|
+
: T extends GeneratedRunSummary
|
|
552
|
+
? RunSummary
|
|
553
|
+
: T extends Blob
|
|
554
|
+
? Blob
|
|
555
|
+
: T extends Promise<infer Value>
|
|
556
|
+
? Promise<PublicOutput<Value>>
|
|
557
|
+
: T extends AsyncGenerator<infer Value, infer Return, infer Next>
|
|
558
|
+
? AsyncGenerator<PublicOutput<Value>, PublicOutput<Return>, Next>
|
|
559
|
+
: T extends readonly unknown[]
|
|
560
|
+
? { [K in keyof T]: PublicOutput<T[K]> }
|
|
561
|
+
: T extends object
|
|
562
|
+
? { [K in keyof T]: PublicOutput<T[K]> }
|
|
563
|
+
: T;
|
|
490
564
|
|
|
491
565
|
type PublicClientMember<T> = T extends (...args: infer Args) => infer Result
|
|
492
566
|
? (...args: { [K in keyof Args]: PublicInput<Args[K]> }) => PublicOutput<Result>
|
package/src/errors.ts
CHANGED
|
@@ -1,28 +1,43 @@
|
|
|
1
|
-
export type PotatoApiErrorCode =
|
|
1
|
+
export type PotatoApiErrorCode = "http" | "wait_timeout";
|
|
2
2
|
|
|
3
3
|
export class PotatoApiError extends Error {
|
|
4
4
|
readonly code: PotatoApiErrorCode;
|
|
5
5
|
readonly status: number | undefined;
|
|
6
6
|
readonly body: unknown;
|
|
7
|
+
readonly requestId: string | undefined;
|
|
7
8
|
|
|
8
|
-
private constructor(
|
|
9
|
+
private constructor(
|
|
10
|
+
message: string,
|
|
11
|
+
code: PotatoApiErrorCode,
|
|
12
|
+
status: number | undefined,
|
|
13
|
+
body: unknown,
|
|
14
|
+
requestId?: string,
|
|
15
|
+
) {
|
|
9
16
|
super(message);
|
|
10
|
-
this.name =
|
|
17
|
+
this.name = "PotatoApiError";
|
|
11
18
|
this.code = code;
|
|
12
19
|
this.status = status;
|
|
13
20
|
this.body = body;
|
|
21
|
+
this.requestId = requestId;
|
|
14
22
|
}
|
|
15
23
|
|
|
16
|
-
static fromResponse(status: number, body: unknown) {
|
|
17
|
-
|
|
24
|
+
static fromResponse(status: number, body: unknown, requestId?: string) {
|
|
25
|
+
const requestSuffix = requestId === undefined ? "" : ` (request id: ${requestId})`;
|
|
26
|
+
return new PotatoApiError(
|
|
27
|
+
`Potato API request failed with status ${status}${requestSuffix}`,
|
|
28
|
+
"http",
|
|
29
|
+
status,
|
|
30
|
+
body,
|
|
31
|
+
requestId,
|
|
32
|
+
);
|
|
18
33
|
}
|
|
19
34
|
|
|
20
35
|
static waitTimeout(timeoutMs: number) {
|
|
21
36
|
return new PotatoApiError(
|
|
22
37
|
`Potato API job did not reach a terminal status within ${timeoutMs} ms`,
|
|
23
|
-
|
|
38
|
+
"wait_timeout",
|
|
24
39
|
undefined,
|
|
25
|
-
{ timeoutMs }
|
|
40
|
+
{ timeoutMs },
|
|
26
41
|
);
|
|
27
42
|
}
|
|
28
43
|
}
|
|
@@ -33,17 +48,17 @@ export type PipelineGraphValidationIssue = {
|
|
|
33
48
|
};
|
|
34
49
|
|
|
35
50
|
export class PipelineGraphValidationError extends Error {
|
|
36
|
-
readonly code =
|
|
51
|
+
readonly code = "invalid_pipeline_graph";
|
|
37
52
|
readonly issues: readonly PipelineGraphValidationIssue[];
|
|
38
53
|
|
|
39
54
|
private constructor(message: string, issues: readonly PipelineGraphValidationIssue[]) {
|
|
40
55
|
super(message);
|
|
41
|
-
this.name =
|
|
56
|
+
this.name = "PipelineGraphValidationError";
|
|
42
57
|
this.issues = issues;
|
|
43
58
|
}
|
|
44
59
|
|
|
45
60
|
static fromIssues(issues: readonly PipelineGraphValidationIssue[]) {
|
|
46
|
-
const details = issues.map(({ path, reason }) => `- ${path}: ${reason}`).join(
|
|
61
|
+
const details = issues.map(({ path, reason }) => `- ${path}: ${reason}`).join("\n");
|
|
47
62
|
return new PipelineGraphValidationError(`Pipeline graph validation failed\n${details}`, issues);
|
|
48
63
|
}
|
|
49
64
|
}
|
package/src/transport.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { assert } from
|
|
2
|
-
import { PotatoApiError } from
|
|
1
|
+
import { assert } from "es-toolkit";
|
|
2
|
+
import { PotatoApiError } from "./errors";
|
|
3
3
|
|
|
4
|
-
const BASE_URL_HEADER =
|
|
4
|
+
const BASE_URL_HEADER = "x-potato-sdk-base-url";
|
|
5
5
|
|
|
6
6
|
type TransportRequestInit = RequestInit & {
|
|
7
7
|
readonly fetch?: typeof globalThis.fetch;
|
|
@@ -10,18 +10,18 @@ type TransportRequestInit = RequestInit & {
|
|
|
10
10
|
export const createRequestOptions = (
|
|
11
11
|
baseUrl: string,
|
|
12
12
|
apiKey: string,
|
|
13
|
-
fetch?: typeof globalThis.fetch
|
|
13
|
+
fetch?: typeof globalThis.fetch,
|
|
14
14
|
): TransportRequestInit => {
|
|
15
|
-
assert(baseUrl.length > 0,
|
|
16
|
-
assert(apiKey.length > 0,
|
|
15
|
+
assert(baseUrl.length > 0, "The SDK base URL cannot be empty");
|
|
16
|
+
assert(apiKey.length > 0, "The SDK API key cannot be empty");
|
|
17
17
|
|
|
18
18
|
return {
|
|
19
19
|
headers: {
|
|
20
|
-
Accept:
|
|
20
|
+
Accept: "application/json",
|
|
21
21
|
Authorization: `ApiKey ${apiKey}`,
|
|
22
|
-
[BASE_URL_HEADER]: new URL(baseUrl).toString()
|
|
22
|
+
[BASE_URL_HEADER]: new URL(baseUrl).toString(),
|
|
23
23
|
},
|
|
24
|
-
fetch
|
|
24
|
+
fetch,
|
|
25
25
|
};
|
|
26
26
|
};
|
|
27
27
|
|
|
@@ -30,7 +30,7 @@ export async function potatoFetch(url: string, options: TransportRequestInit): P
|
|
|
30
30
|
const { fetch: fetchImplementation = globalThis.fetch, ...requestOptions } = options;
|
|
31
31
|
const headers = new Headers(requestOptions.headers);
|
|
32
32
|
const baseUrl = headers.get(BASE_URL_HEADER);
|
|
33
|
-
assert(baseUrl,
|
|
33
|
+
assert(baseUrl, "The SDK base URL is missing");
|
|
34
34
|
headers.delete(BASE_URL_HEADER);
|
|
35
35
|
|
|
36
36
|
const response = await fetchImplementation(new URL(url, baseUrl), { ...requestOptions, headers });
|
|
@@ -41,13 +41,16 @@ export async function potatoFetch(url: string, options: TransportRequestInit): P
|
|
|
41
41
|
|
|
42
42
|
if (text.length === 0) {
|
|
43
43
|
body = undefined;
|
|
44
|
-
} else if (response.headers.get(
|
|
44
|
+
} else if (response.headers.get("content-type")?.includes("application/json")) {
|
|
45
45
|
body = JSON.parse(text);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
throw PotatoApiError.fromResponse(
|
|
48
|
+
throw PotatoApiError.fromResponse(
|
|
49
|
+
response.status,
|
|
50
|
+
body,
|
|
51
|
+
response.headers.get("x-request-id") ?? undefined,
|
|
52
|
+
);
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
return text.length === 0 ? undefined : JSON.parse(text);
|
|
52
56
|
}
|
|
53
|
-
|