@toloka-platform/sdk 0.11.2 → 0.11.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/toloka.js +158 -154
- package/dist/cli/toloka.js.jsc +0 -0
- package/dist/cli/toloka.js.jsc.sha256 +1 -1
- package/dist/cli/toloka.js.sha256 +1 -1
- package/docs/authoring.md +6 -4
- package/docs/cli.md +30 -11
- package/docs/limitations.md +2 -2
- package/docs/testing.md +4 -2
- package/examples/README.md +11 -0
- package/examples/app-crowdtesting/README.md +41 -0
- package/examples/app-crowdtesting/fields.ts +6 -0
- package/examples/app-crowdtesting/nodes/app-flow-test/node.ts +381 -0
- package/examples/app-crowdtesting/nodes/collection/node.ts +8 -0
- package/examples/app-crowdtesting/pipeline.browser.integration.spec.ts +77 -0
- package/examples/app-crowdtesting/pipeline.ts +17 -0
- package/examples/egocentric-video-collection/README.md +35 -0
- package/examples/egocentric-video-collection/fields.ts +24 -0
- package/examples/egocentric-video-collection/nodes/collection/node.ts +5 -0
- package/examples/egocentric-video-collection/nodes/record-activity/node.ts +760 -0
- package/examples/egocentric-video-collection/pipeline.browser.integration.spec.ts +65 -0
- package/examples/egocentric-video-collection/pipeline.ts +17 -0
- package/examples/product-moderation/README.md +49 -0
- package/examples/product-moderation/fields.ts +37 -0
- package/examples/product-moderation/nodes/collection/node.ts +16 -0
- package/examples/product-moderation/nodes/moderate-product/instruction.ts +77 -0
- package/examples/product-moderation/nodes/moderate-product/node.ts +368 -0
- package/examples/product-moderation/pipeline.browser.integration.spec.ts +48 -0
- package/examples/product-moderation/pipeline.ts +33 -0
- package/examples/video-pair-rating/fields.ts +16 -4
- package/examples/video-pair-rating/nodes/adjudicate/node.ts +78 -3
- package/examples/video-pair-rating/nodes/adjudicate_op/node.ts +28 -3
- package/examples/video-pair-rating/nodes/overall_preference_pick/node.ts +28 -3
- package/examples/video-pair-rating/nodes/rate_pair/node.ts +65 -2
- package/openapi/gen/api.ts +22 -0
- package/openapi/gen/models/generationBudget.ts +8 -0
- package/openapi/gen/models/generationBudgetReasoningEffort.ts +2 -0
- package/openapi/gen/models/generationModel.ts +12 -0
- package/openapi/gen/models/generationModelDefaultReasoningEffort.ts +2 -0
- package/openapi/gen/models/generationModelId.ts +2 -0
- package/openapi/gen/models/index.ts +8 -0
- package/openapi/gen/models/invalidFieldSchema.ts +6 -0
- package/openapi/gen/models/listGenerationModels200.ts +7 -0
- package/openapi/gen/models/listGenerationModels200DefaultGenerationModelId.ts +2 -0
- package/openapi/gen/models/pipelineGraphSnapshot.ts +2 -0
- package/package.json +2 -2
- package/skills/catalog.json +16 -12
- package/skills/toloka-build/SKILL.md +44 -58
- package/skills/toloka-build/references/human-work.md +156 -0
- package/skills/toloka-build/references/local-setup.md +136 -0
- package/skills/toloka-build/references/node-checks.md +11 -0
- package/skills/toloka-build/references/node-semantics.md +22 -213
- package/skills/toloka-build/references/task-ui.md +61 -0
- package/skills/toloka-build/references/workflow-and-cli.md +34 -228
- package/skills/toloka-fine-tuning/SKILL.md +1 -1
- package/skills/toloka-get-started/SKILL.md +1 -1
- package/skills/toloka-gisting/SKILL.md +1 -1
- package/src/authoring/index.ts +26 -7
- package/src/checks/task-ui-typecheck.ts +3 -3
- package/src/cli/analytics.ts +1 -0
- package/src/cli/check.ts +83 -12
- package/src/cli/commands/generation-model.ts +18 -0
- package/src/cli/commands/pipeline.ts +1 -1
- package/src/cli/commands/source.ts +14 -3
- package/src/cli/data.ts +5 -2
- package/src/cli/format-error.ts +3 -0
- package/src/cli/generation-models.ts +46 -0
- package/src/cli/program.ts +2 -0
- package/src/cli/project.ts +288 -138
- package/src/cli/trainings.ts +12 -0
- package/src/cli/ui.ts +3 -1
- package/src/client.ts +5 -0
- package/src/graph-rules.json +11 -0
- package/src/importer.ts +46 -40
- package/src/index.ts +4 -0
- package/src/transport.ts +23 -5
- package/src/validate.ts +183 -0
package/src/cli/check.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
type TestEvidence,
|
|
24
24
|
type TestEvidenceKind,
|
|
25
25
|
} from "../testing/test-evidence";
|
|
26
|
+
import { platformRuleIssues } from "../validate";
|
|
26
27
|
import { cliRelaunchCommand } from "./cli-entry";
|
|
27
28
|
import { bunSubprocessEnvironment } from "./native-runtime";
|
|
28
29
|
import { CREDENTIAL_ENVIRONMENT_NAMES } from "./environment";
|
|
@@ -30,7 +31,13 @@ import { loadProjectSource, type ProjectSource } from "./source";
|
|
|
30
31
|
import { assertCli, REPORT_HINT, TolokaCliError } from "./cli-error";
|
|
31
32
|
import type { TolokaCliErrorOptions } from "./cli-error";
|
|
32
33
|
|
|
33
|
-
export type CheckStatus =
|
|
34
|
+
export type CheckStatus =
|
|
35
|
+
| "passed"
|
|
36
|
+
| "failed"
|
|
37
|
+
| "missing"
|
|
38
|
+
| "partial"
|
|
39
|
+
| "warning"
|
|
40
|
+
| "infrastructure_error";
|
|
34
41
|
export type CheckKind =
|
|
35
42
|
| "source"
|
|
36
43
|
| "project-types"
|
|
@@ -38,6 +45,7 @@ export type CheckKind =
|
|
|
38
45
|
| "code-test"
|
|
39
46
|
| "ui-test"
|
|
40
47
|
| "pipeline-flow"
|
|
48
|
+
| "platform-rules"
|
|
41
49
|
| "test-runner";
|
|
42
50
|
|
|
43
51
|
export type CheckDiagnostic = {
|
|
@@ -504,6 +512,39 @@ const uiTypeResults = async (
|
|
|
504
512
|
return results;
|
|
505
513
|
};
|
|
506
514
|
|
|
515
|
+
const platformRuleResults = (
|
|
516
|
+
source: ProjectSource,
|
|
517
|
+
selected: readonly CheckInventoryPipeline[],
|
|
518
|
+
): CheckResult[] => {
|
|
519
|
+
const selectedDirectories = new Set(selected.map((pipeline) => pipeline.sourceDirectory));
|
|
520
|
+
return source.pipelines
|
|
521
|
+
.filter((pipeline) => selectedDirectories.has(pipeline.sourceDirectory))
|
|
522
|
+
.map((pipeline) => {
|
|
523
|
+
const issues = platformRuleIssues(pipeline.definition.graph);
|
|
524
|
+
return {
|
|
525
|
+
scope: "pipeline",
|
|
526
|
+
kind: "platform-rules",
|
|
527
|
+
status: issues.length === 0 ? "passed" : "warning",
|
|
528
|
+
sourceDirectory: pipeline.sourceDirectory,
|
|
529
|
+
pipelineFingerprint: pipelineFingerprint(pipeline.definition),
|
|
530
|
+
...boundedDiagnostics(
|
|
531
|
+
issues.length === 0
|
|
532
|
+
? []
|
|
533
|
+
: [
|
|
534
|
+
...issues.map((issue) => ({
|
|
535
|
+
message: `node ${issue.node}: ${issue.reason}`,
|
|
536
|
+
severity: "warning" as const,
|
|
537
|
+
})),
|
|
538
|
+
{
|
|
539
|
+
message: "toloka apply refuses to write this pipeline until these are fixed.",
|
|
540
|
+
severity: "warning" as const,
|
|
541
|
+
},
|
|
542
|
+
],
|
|
543
|
+
),
|
|
544
|
+
};
|
|
545
|
+
});
|
|
546
|
+
};
|
|
547
|
+
|
|
507
548
|
const evidenceStatus = (
|
|
508
549
|
evidence: readonly TestEvidence[],
|
|
509
550
|
): Pick<CheckResult, "status" | "diagnostics" | "truncatedDiagnosticCount"> => {
|
|
@@ -536,9 +577,9 @@ const evidenceStatus = (
|
|
|
536
577
|
status: "partial",
|
|
537
578
|
diagnostics: [
|
|
538
579
|
{
|
|
539
|
-
message: `Hardware-backed fields not
|
|
580
|
+
message: `Hardware-backed fields not covered by a real device: ${[
|
|
540
581
|
...new Set(passing.flatMap((entry) => entry.untestedHardwareFields ?? [])),
|
|
541
|
-
].join(", ")}
|
|
582
|
+
].join(", ")}. This does not block apply; try the task on a real device before launching a run.`,
|
|
542
583
|
},
|
|
543
584
|
],
|
|
544
585
|
};
|
|
@@ -559,6 +600,38 @@ const evidenceFor = (
|
|
|
559
600
|
(nodeId === undefined || entry.nodeId === nodeId),
|
|
560
601
|
);
|
|
561
602
|
|
|
603
|
+
const typedTestUsage: Record<TestEvidenceKind, { call: string; counts: string }> = {
|
|
604
|
+
code: { call: "test.code(pipeline, node, name, callback)", counts: "runs the node" },
|
|
605
|
+
ui: { call: "test.ui(pipeline, node, name, callback)", counts: "submits the rendered task" },
|
|
606
|
+
pipeline: { call: "test.pipeline(pipeline, name, callback)", counts: "runs the connected nodes" },
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
const coverageStatus = (
|
|
610
|
+
evidence: readonly TestEvidence[],
|
|
611
|
+
inventory: readonly CheckInventoryPipeline[],
|
|
612
|
+
pipeline: CheckInventoryPipeline,
|
|
613
|
+
kind: TestEvidenceKind,
|
|
614
|
+
nodeId?: string,
|
|
615
|
+
): Pick<CheckResult, "status" | "diagnostics" | "truncatedDiagnosticCount"> => {
|
|
616
|
+
const status = evidenceStatus(evidenceFor(evidence, pipeline, kind, nodeId));
|
|
617
|
+
if (status.status !== "missing") return status;
|
|
618
|
+
const target = nodeId === undefined ? "this pipeline" : "this node";
|
|
619
|
+
const { call, counts } = typedTestUsage[kind];
|
|
620
|
+
const knownFingerprints = new Set(inventory.map((candidate) => candidate.pipelineFingerprint));
|
|
621
|
+
const strayTests = evidence.filter(
|
|
622
|
+
(entry) =>
|
|
623
|
+
entry.kind === kind &&
|
|
624
|
+
entry.status === "passed" &&
|
|
625
|
+
entry.nodeId === nodeId &&
|
|
626
|
+
!knownFingerprints.has(entry.pipelineFingerprint),
|
|
627
|
+
);
|
|
628
|
+
const message =
|
|
629
|
+
strayTests.length > 0
|
|
630
|
+
? `Passing ${kind} tests for ${target} (${strayTests.length}) ran against a different pipeline definition than the one ${pipeline.sourceDirectory}/pipeline.ts exports and do not count. Pass that exported pipeline to the test instead of building one inside the test.`
|
|
631
|
+
: `No passing ${kind} test covers ${target}. Add ${call} with the pipeline ${pipeline.sourceDirectory}/pipeline.ts exports; it counts once it ${counts}, makes an assertion, and passes.`;
|
|
632
|
+
return { status: "missing", diagnostics: [{ message }] };
|
|
633
|
+
};
|
|
634
|
+
|
|
562
635
|
const coverageResults = (
|
|
563
636
|
inventory: readonly CheckInventoryPipeline[],
|
|
564
637
|
evidence: readonly TestEvidence[],
|
|
@@ -576,7 +649,7 @@ const coverageResults = (
|
|
|
576
649
|
sourceDirectory: pipeline.sourceDirectory,
|
|
577
650
|
pipelineFingerprint: pipeline.pipelineFingerprint,
|
|
578
651
|
nodeId: node.id,
|
|
579
|
-
...
|
|
652
|
+
...coverageStatus(evidence, inventory, pipeline, evidenceKind, node.id),
|
|
580
653
|
});
|
|
581
654
|
}
|
|
582
655
|
if (nodeSelector === undefined) {
|
|
@@ -585,7 +658,7 @@ const coverageResults = (
|
|
|
585
658
|
kind: "pipeline-flow",
|
|
586
659
|
sourceDirectory: pipeline.sourceDirectory,
|
|
587
660
|
pipelineFingerprint: pipeline.pipelineFingerprint,
|
|
588
|
-
...
|
|
661
|
+
...coverageStatus(evidence, inventory, pipeline, "pipeline"),
|
|
589
662
|
});
|
|
590
663
|
}
|
|
591
664
|
return result;
|
|
@@ -596,6 +669,7 @@ const statusLabel: Record<CheckStatus, string> = {
|
|
|
596
669
|
failed: "FAIL",
|
|
597
670
|
missing: "MISSING",
|
|
598
671
|
partial: "PARTIAL",
|
|
672
|
+
warning: "WARN",
|
|
599
673
|
infrastructure_error: "ERROR",
|
|
600
674
|
};
|
|
601
675
|
|
|
@@ -629,13 +703,7 @@ export const formatCheckResults = (results: readonly CheckResult[]): string =>
|
|
|
629
703
|
|
|
630
704
|
const exitCodeForResults = (results: readonly CheckResult[]): 0 | 1 | 2 => {
|
|
631
705
|
if (results.some((result) => result.status === "infrastructure_error")) return 2;
|
|
632
|
-
if (
|
|
633
|
-
results.some(
|
|
634
|
-
(result) =>
|
|
635
|
-
result.status === "failed" || result.status === "missing" || result.status === "partial",
|
|
636
|
-
)
|
|
637
|
-
)
|
|
638
|
-
return 1;
|
|
706
|
+
if (results.some((result) => result.status === "failed" || result.status === "missing")) return 1;
|
|
639
707
|
return 0;
|
|
640
708
|
};
|
|
641
709
|
|
|
@@ -723,6 +791,7 @@ export async function checkProject(
|
|
|
723
791
|
...uiResults,
|
|
724
792
|
projectToolResult("test-runner", vitestRun),
|
|
725
793
|
...coverageResults(selected.pipelines, evidence, selected.nodeId),
|
|
794
|
+
...(selected.nodeId === undefined ? platformRuleResults(source, selected.pipelines) : []),
|
|
726
795
|
]);
|
|
727
796
|
const exitCode = exitCodeForResults(results);
|
|
728
797
|
return {
|
|
@@ -787,6 +856,7 @@ const isCheckKind = (value: unknown): value is CheckKind =>
|
|
|
787
856
|
value === "code-test" ||
|
|
788
857
|
value === "ui-test" ||
|
|
789
858
|
value === "pipeline-flow" ||
|
|
859
|
+
value === "platform-rules" ||
|
|
790
860
|
value === "test-runner";
|
|
791
861
|
|
|
792
862
|
const isCheckStatus = (value: unknown): value is CheckStatus =>
|
|
@@ -794,6 +864,7 @@ const isCheckStatus = (value: unknown): value is CheckStatus =>
|
|
|
794
864
|
value === "failed" ||
|
|
795
865
|
value === "missing" ||
|
|
796
866
|
value === "partial" ||
|
|
867
|
+
value === "warning" ||
|
|
797
868
|
value === "infrastructure_error";
|
|
798
869
|
|
|
799
870
|
const parseFreshCheckDiagnostic = (value: unknown): CheckDiagnostic => {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import { resolveContext, type CommandHost } from "../context";
|
|
3
|
+
import { listGenerationModels } from "../generation-models";
|
|
4
|
+
|
|
5
|
+
export const registerGenerationModelCommands = (program: Command, host: CommandHost): void => {
|
|
6
|
+
const { context, globals } = host;
|
|
7
|
+
|
|
8
|
+
program
|
|
9
|
+
.command("generation-model")
|
|
10
|
+
.description("inspect the models synthetic generation nodes can use")
|
|
11
|
+
.command("list")
|
|
12
|
+
.option("--json", "print JSON", false)
|
|
13
|
+
.description("list generation models with reasoning efforts and maxCostPerAttempt bounds")
|
|
14
|
+
.action(async (options: { json: boolean }) => {
|
|
15
|
+
const { client } = await resolveContext(globals(), context);
|
|
16
|
+
await listGenerationModels(client, { json: options.json }, context.io);
|
|
17
|
+
});
|
|
18
|
+
};
|
|
@@ -38,7 +38,7 @@ export const registerPipelineCommands = (program: Command, host: CommandHost): v
|
|
|
38
38
|
.argument("[name]", pipelineNameHelp)
|
|
39
39
|
.option("--wait", "wait for the run to reach a terminal state", false)
|
|
40
40
|
.option("--timeout <ms>", "how long to wait", positiveInteger)
|
|
41
|
-
.description("start a run on
|
|
41
|
+
.description("start a run on an applied pipeline")
|
|
42
42
|
.action(async (name: string | undefined, options: { wait: boolean; timeout?: number }) => {
|
|
43
43
|
const { client, state, projectId } = await resolveContext(globals(), context);
|
|
44
44
|
assertProjectSelected(projectId);
|
|
@@ -14,6 +14,9 @@ import { applyProject, importProject, planProject, validateProject } from "../pr
|
|
|
14
14
|
import { assertProjectSelected, resolveProjectContext } from "../project-context";
|
|
15
15
|
import { readTolokaState } from "../../state";
|
|
16
16
|
import { assertCli, REPORT_HINT } from "../cli-error";
|
|
17
|
+
import { writeOutput } from "../table";
|
|
18
|
+
|
|
19
|
+
const VALIDATE_WAIT = { timeoutMs: 5 * 60_000, pollIntervalMs: 5_000 };
|
|
17
20
|
|
|
18
21
|
const runChecksInterruptibly = async (
|
|
19
22
|
options: CheckProjectOptions,
|
|
@@ -88,24 +91,32 @@ export const registerSourceCommands = (program: Command, host: CommandHost): voi
|
|
|
88
91
|
|
|
89
92
|
program
|
|
90
93
|
.command("plan")
|
|
94
|
+
.option("--json", "print the planned changes and missing secrets as JSON", false)
|
|
91
95
|
.description("show what apply would change")
|
|
92
|
-
.action(async () => {
|
|
96
|
+
.action(async (options: { json: boolean }) => {
|
|
93
97
|
const { sourceRoot, client, projectId } = await resolveContext(globals(), context);
|
|
94
98
|
const result = await planProject(client, {
|
|
95
99
|
sourceRoot,
|
|
96
100
|
...(projectId === undefined ? {} : { projectId }),
|
|
97
101
|
});
|
|
98
|
-
|
|
102
|
+
writeOutput(
|
|
103
|
+
context.io,
|
|
104
|
+
options.json,
|
|
105
|
+
{ changes: result.changes, missingSecrets: result.missingSecrets },
|
|
106
|
+
result.output,
|
|
107
|
+
);
|
|
99
108
|
});
|
|
100
109
|
|
|
101
110
|
program
|
|
102
111
|
.command("validate")
|
|
112
|
+
.option("--wait", "wait up to 5 minutes for running lints and checks to finish", false)
|
|
103
113
|
.description("run platform spec validation and report matching checks")
|
|
104
|
-
.action(async () => {
|
|
114
|
+
.action(async (options: { wait: boolean }) => {
|
|
105
115
|
const { sourceRoot, client, projectId } = await resolveContext(globals(), context);
|
|
106
116
|
const result = await validateProject(client, {
|
|
107
117
|
sourceRoot,
|
|
108
118
|
...(projectId === undefined ? {} : { projectId }),
|
|
119
|
+
...(options.wait ? { wait: VALIDATE_WAIT } : {}),
|
|
109
120
|
});
|
|
110
121
|
context.io.stdout(result.output);
|
|
111
122
|
if (!result.valid) exitCode.value = 1;
|
package/src/cli/data.ts
CHANGED
|
@@ -132,7 +132,7 @@ const summarizeJsonSchema = (schema: unknown): string => {
|
|
|
132
132
|
const formatInferredFields = (fields: ReadonlyArray<InferredField>): string => {
|
|
133
133
|
if (fields.length === 0) return "No inferred fields are available yet.";
|
|
134
134
|
return [
|
|
135
|
-
"
|
|
135
|
+
"Types inferred from the uploaded rows (not the column schemas, which keep the constraints declared in source):",
|
|
136
136
|
...fields
|
|
137
137
|
.toSorted((left, right) => left.jsonPath.localeCompare(right.jsonPath))
|
|
138
138
|
.map(
|
|
@@ -459,6 +459,9 @@ export async function uploadDataset(
|
|
|
459
459
|
};
|
|
460
460
|
}
|
|
461
461
|
|
|
462
|
+
const INFERRED_DECLARATIONS_NOTE =
|
|
463
|
+
"// Inferred from the uploaded rows: enum, length, range and format constraints are not inferred, so these are not the dataset's column schemas.";
|
|
464
|
+
|
|
462
465
|
export async function generateDatasetFieldDeclarations(
|
|
463
466
|
client: PotatoClient,
|
|
464
467
|
options: GenerateDatasetFieldDeclarationsOptions,
|
|
@@ -476,7 +479,7 @@ export async function generateDatasetFieldDeclarations(
|
|
|
476
479
|
output:
|
|
477
480
|
topLevelFields.length === 0
|
|
478
481
|
? `Dataset ${resolved.name} has no inferred fields yet.`
|
|
479
|
-
: declarations
|
|
482
|
+
: `${INFERRED_DECLARATIONS_NOTE}\n${declarations}`,
|
|
480
483
|
};
|
|
481
484
|
}
|
|
482
485
|
|
package/src/cli/format-error.ts
CHANGED
|
@@ -24,6 +24,9 @@ const apiErrorHint = (error: PotatoApiError): string | undefined => {
|
|
|
24
24
|
if (error.status === 429) {
|
|
25
25
|
return "Hint: The platform is rate limiting this key; wait a moment and retry.";
|
|
26
26
|
}
|
|
27
|
+
if (error.status === 503 && error.body === "Tunnel unavailable; the request was not sent") {
|
|
28
|
+
return "Hint: The sandbox lost its connection to the platform (usually a platform restart) and it was not restored within 90 seconds; the request was not sent. Retry in a minute.";
|
|
29
|
+
}
|
|
27
30
|
if (error.status !== undefined && error.status >= 500) {
|
|
28
31
|
return "Hint: The platform failed to handle the request. Retry; if it keeps failing, write a report as the toloka-report-issue skill describes and send it with toloka report <report.md>.";
|
|
29
32
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { PotatoClient } from "../client";
|
|
2
|
+
import { formatTable, type TableIo, writeOutput } from "./table";
|
|
3
|
+
|
|
4
|
+
type GenerationModelApi = Pick<PotatoClient, "generationModels">;
|
|
5
|
+
|
|
6
|
+
const dollars = (amount: number): string => `$${amount.toFixed(2)}`;
|
|
7
|
+
|
|
8
|
+
export const listGenerationModels = async (
|
|
9
|
+
client: GenerationModelApi,
|
|
10
|
+
input: { json: boolean },
|
|
11
|
+
io: TableIo,
|
|
12
|
+
): Promise<void> => {
|
|
13
|
+
const catalog = await client.generationModels.list();
|
|
14
|
+
const recommended = catalog.generationModels
|
|
15
|
+
.filter((model) => model.recommended)
|
|
16
|
+
.map((model) => model.id);
|
|
17
|
+
writeOutput(
|
|
18
|
+
io,
|
|
19
|
+
input.json,
|
|
20
|
+
catalog,
|
|
21
|
+
catalog.generationModels.length === 0
|
|
22
|
+
? "No generation models available."
|
|
23
|
+
: [
|
|
24
|
+
formatTable([
|
|
25
|
+
["ID", "NAME", "REASONING EFFORT", "TYPICAL", "MIN", "MAX"],
|
|
26
|
+
...catalog.generationModels.flatMap((model) =>
|
|
27
|
+
model.budgets.map((budget) => [
|
|
28
|
+
model.id,
|
|
29
|
+
model.displayName,
|
|
30
|
+
budget.reasoningEffort === undefined
|
|
31
|
+
? "-"
|
|
32
|
+
: budget.reasoningEffort === model.defaultReasoningEffort
|
|
33
|
+
? `${budget.reasoningEffort} (default)`
|
|
34
|
+
: budget.reasoningEffort,
|
|
35
|
+
dollars(budget.typical),
|
|
36
|
+
dollars(budget.min),
|
|
37
|
+
dollars(budget.maxEstimate),
|
|
38
|
+
]),
|
|
39
|
+
),
|
|
40
|
+
]),
|
|
41
|
+
"",
|
|
42
|
+
`Default model: ${catalog.defaultGenerationModelId}`,
|
|
43
|
+
...(recommended.length === 0 ? [] : [`Recommended: ${recommended.join(", ")}`]),
|
|
44
|
+
].join("\n"),
|
|
45
|
+
);
|
|
46
|
+
};
|
package/src/cli/program.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { registerAudienceCommands } from "./commands/audience";
|
|
|
11
11
|
import { registerAuthCommands } from "./commands/auth";
|
|
12
12
|
import { registerConfigCommands } from "./commands/config";
|
|
13
13
|
import { registerDatasetCommands } from "./commands/dataset";
|
|
14
|
+
import { registerGenerationModelCommands } from "./commands/generation-model";
|
|
14
15
|
import { registerDeliveryOrderCommands } from "./commands/delivery-order";
|
|
15
16
|
import { registerModelCommands } from "./commands/models";
|
|
16
17
|
import { registerPipelineCommands } from "./commands/pipeline";
|
|
@@ -96,6 +97,7 @@ export function createProgram(context: ProgramContext): CreatedProgram {
|
|
|
96
97
|
registerProjectCommands(program, host);
|
|
97
98
|
registerDeliveryOrderCommands(program, host);
|
|
98
99
|
registerAudienceCommands(program, host);
|
|
100
|
+
registerGenerationModelCommands(program, host);
|
|
99
101
|
registerSourceCommands(program, host);
|
|
100
102
|
registerSecretCommands(program, host);
|
|
101
103
|
registerModelCommands(program, host);
|