dataiku-sdk 3.6.1 → 3.7.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 (127) hide show
  1. package/README.md +14 -6
  2. package/bin/bun-version.js +14 -0
  3. package/bin/dss.js +11 -15
  4. package/dist/build-metadata.json +1 -1
  5. package/dist/packages/types/src/index.d.ts +74 -1
  6. package/dist/packages/types/src/index.js +53 -1
  7. package/dist/src/cli/coerce.d.ts +1 -0
  8. package/dist/src/cli/coerce.js +19 -15
  9. package/dist/src/cli/command-syntax.json +3521 -416
  10. package/dist/src/cli/commands/analysis.js +19 -1
  11. package/dist/src/cli/commands/bundle.js +22 -0
  12. package/dist/src/cli/commands/connection.js +26 -2
  13. package/dist/src/cli/commands/data-quality.js +33 -1
  14. package/dist/src/cli/commands/dataset.js +35 -4
  15. package/dist/src/cli/commands/discussion.js +15 -0
  16. package/dist/src/cli/commands/doctor.js +1 -1
  17. package/dist/src/cli/commands/flow.d.ts +5 -0
  18. package/dist/src/cli/commands/flow.js +57 -0
  19. package/dist/src/cli/commands/future.js +8 -0
  20. package/dist/src/cli/commands/index.js +6 -0
  21. package/dist/src/cli/commands/job.js +29 -6
  22. package/dist/src/cli/commands/metrics.js +21 -1
  23. package/dist/src/cli/commands/ml-task.d.ts +5 -0
  24. package/dist/src/cli/commands/ml-task.js +86 -16
  25. package/dist/src/cli/commands/mlflow.d.ts +11 -0
  26. package/dist/src/cli/commands/mlflow.js +121 -0
  27. package/dist/src/cli/commands/plugin.js +5 -11
  28. package/dist/src/cli/commands/project-deployer.js +70 -0
  29. package/dist/src/cli/commands/project-library.js +2 -5
  30. package/dist/src/cli/commands/project.js +8 -0
  31. package/dist/src/cli/commands/recipe.d.ts +9 -0
  32. package/dist/src/cli/commands/recipe.js +93 -7
  33. package/dist/src/cli/commands/saved-model.d.ts +1 -1
  34. package/dist/src/cli/commands/saved-model.js +9 -76
  35. package/dist/src/cli/commands/streaming-endpoint.js +30 -1
  36. package/dist/src/cli/commands/webapp.js +8 -0
  37. package/dist/src/cli/commands/wiki.js +22 -0
  38. package/dist/src/cli/commands/workspace.js +8 -0
  39. package/dist/src/cli/contract.d.ts +16 -15
  40. package/dist/src/cli/contract.js +139 -3404
  41. package/dist/src/cli/doctor.d.ts +13 -0
  42. package/dist/src/cli/doctor.js +41 -1
  43. package/dist/src/cli/flags.d.ts +7 -1
  44. package/dist/src/cli/flags.js +78 -6
  45. package/dist/src/cli/helpers/app-successor.js +1 -2
  46. package/dist/src/cli/helpers/documentation.d.ts +21 -0
  47. package/dist/src/cli/helpers/documentation.js +53 -0
  48. package/dist/src/cli/helpers/trained-model.d.ts +26 -0
  49. package/dist/src/cli/helpers/trained-model.js +144 -0
  50. package/dist/src/cli/list-output.d.ts +7 -0
  51. package/dist/src/cli/list-output.js +77 -0
  52. package/dist/src/cli/list-shapes.d.ts +21 -0
  53. package/dist/src/cli/list-shapes.js +111 -0
  54. package/dist/src/cli/output-schemas.d.ts +0 -14
  55. package/dist/src/cli/output-schemas.js +4 -7
  56. package/dist/src/cli/output.d.ts +0 -1
  57. package/dist/src/cli/output.js +27 -19
  58. package/dist/src/cli/plans.d.ts +14 -0
  59. package/dist/src/cli/plans.js +3684 -0
  60. package/dist/src/cli/usage.d.ts +7 -0
  61. package/dist/src/cli/usage.js +20 -1
  62. package/dist/src/cli/version.d.ts +2 -2
  63. package/dist/src/cli/version.js +2 -2
  64. package/dist/src/cli.js +127 -113
  65. package/dist/src/client.d.ts +52 -43
  66. package/dist/src/client.js +267 -96
  67. package/dist/src/errors.d.ts +11 -1
  68. package/dist/src/errors.js +31 -47
  69. package/dist/src/generated/action-output-schemas.json +345 -89
  70. package/dist/src/index.d.ts +5 -1
  71. package/dist/src/index.js +3 -0
  72. package/dist/src/resources/analyses.d.ts +8 -0
  73. package/dist/src/resources/analyses.js +13 -1
  74. package/dist/src/resources/bundles.d.ts +34 -0
  75. package/dist/src/resources/bundles.js +67 -0
  76. package/dist/src/resources/connections.d.ts +9 -0
  77. package/dist/src/resources/connections.js +15 -0
  78. package/dist/src/resources/data-quality.d.ts +20 -0
  79. package/dist/src/resources/data-quality.js +30 -0
  80. package/dist/src/resources/dataset-create.d.ts +19 -0
  81. package/dist/src/resources/dataset-create.js +66 -0
  82. package/dist/src/resources/datasets.d.ts +25 -15
  83. package/dist/src/resources/datasets.js +59 -111
  84. package/dist/src/resources/discussions.d.ts +5 -0
  85. package/dist/src/resources/discussions.js +7 -0
  86. package/dist/src/resources/documentation.d.ts +25 -0
  87. package/dist/src/resources/documentation.js +16 -0
  88. package/dist/src/resources/flow.d.ts +48 -0
  89. package/dist/src/resources/flow.js +65 -0
  90. package/dist/src/resources/futures.d.ts +23 -0
  91. package/dist/src/resources/futures.js +32 -0
  92. package/dist/src/resources/jobs.js +102 -2
  93. package/dist/src/resources/metrics.d.ts +10 -0
  94. package/dist/src/resources/metrics.js +10 -0
  95. package/dist/src/resources/ml-tasks.d.ts +65 -2
  96. package/dist/src/resources/ml-tasks.js +102 -28
  97. package/dist/src/resources/mlflow-extension.d.ts +73 -0
  98. package/dist/src/resources/mlflow-extension.js +105 -0
  99. package/dist/src/resources/projects.d.ts +6 -0
  100. package/dist/src/resources/projects.js +8 -0
  101. package/dist/src/resources/recipe-create.d.ts +65 -0
  102. package/dist/src/resources/recipe-create.js +338 -0
  103. package/dist/src/resources/recipes.d.ts +28 -29
  104. package/dist/src/resources/recipes.js +126 -245
  105. package/dist/src/resources/saved-models.d.ts +10 -6
  106. package/dist/src/resources/saved-models.js +16 -14
  107. package/dist/src/resources/scenarios.js +8 -14
  108. package/dist/src/resources/streaming-endpoints.d.ts +12 -0
  109. package/dist/src/resources/streaming-endpoints.js +15 -0
  110. package/dist/src/resources/trained-model.d.ts +60 -0
  111. package/dist/src/resources/trained-model.js +98 -0
  112. package/dist/src/resources/webapps.d.ts +8 -0
  113. package/dist/src/resources/webapps.js +10 -0
  114. package/dist/src/resources/wiki.d.ts +5 -0
  115. package/dist/src/resources/wiki.js +7 -0
  116. package/dist/src/resources/workspaces.d.ts +2 -0
  117. package/dist/src/resources/workspaces.js +4 -0
  118. package/dist/src/utils/response-file.js +20 -9
  119. package/dist/src/utils/secret-sanitize.d.ts +7 -0
  120. package/dist/src/utils/secret-sanitize.js +46 -0
  121. package/package.json +25 -26
  122. package/plugin.json +1 -1
  123. package/skills/dataiku-dss/SKILL.md +1 -1
  124. package/skills/dataiku-dss/references/authentication.md +3 -1
  125. package/skills/dataiku-dss/references/coding.md +1 -0
  126. package/skills/dataiku-dss/references/discovery.md +4 -6
  127. package/skills/dataiku-dss/references/troubleshooting.md +3 -2
@@ -68,11 +68,24 @@ export interface DoctorResult {
68
68
  tlsVerify: "strict" | "disabled";
69
69
  caCert: "default" | "custom";
70
70
  };
71
+ identity?: DoctorIdentity;
71
72
  permissions?: DoctorPermissions;
72
73
  permissionDetails?: Partial<Record<DoctorPermissionKey, Record<string, unknown>>>;
73
74
  fixtures?: DoctorFixtures;
74
75
  environment?: DoctorEnvironment;
75
76
  }
77
+ /**
78
+ * The identity a DSS API key acts as, from `GET /public/api/auth/info`
79
+ * (no admin privilege required). Explains unexplained 403s: a personal key
80
+ * acts as its owner, a global key shows up as an `api:<id>` identity.
81
+ * Carries no secret material.
82
+ */
83
+ export interface DoctorIdentity {
84
+ authSource?: string;
85
+ authIdentifier?: string;
86
+ groups?: string[];
87
+ userProfile?: string;
88
+ }
76
89
  export declare function errorDetails(error: unknown): Record<string, unknown>;
77
90
  export declare function firstStringField(items: unknown[] | undefined, fields: string[]): string | null;
78
91
  export declare function integrationFlag(name: string): boolean;
@@ -49,6 +49,34 @@ export function doctorEnvironment(projectKey, versionInfo) {
49
49
  },
50
50
  };
51
51
  }
52
+ /**
53
+ * Identity fields this doctor version reports, read from the documented
54
+ * `GET /public/api/auth/info` payload. Everything is optional: the field set
55
+ * varies across DSS versions and absent fields stay absent.
56
+ */
57
+ function doctorIdentityFromAuthInfo(raw) {
58
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
59
+ return undefined;
60
+ const record = raw;
61
+ const groups = Array.isArray(record["groups"])
62
+ ? record["groups"].filter((g) => typeof g === "string")
63
+ : undefined;
64
+ const authSource = typeof record["authSource"] === "string" ? record["authSource"] : undefined;
65
+ const authIdentifier = typeof record["authIdentifier"] === "string"
66
+ ? record["authIdentifier"]
67
+ : undefined;
68
+ const userProfile = typeof record["userProfile"] === "string" ? record["userProfile"] : undefined;
69
+ if (authSource === undefined && authIdentifier === undefined && userProfile === undefined
70
+ && (groups === undefined || groups.length === 0)) {
71
+ return undefined;
72
+ }
73
+ return {
74
+ ...(authSource !== undefined ? { authSource, } : {}),
75
+ ...(authIdentifier !== undefined ? { authIdentifier, } : {}),
76
+ ...(groups !== undefined && groups.length > 0 ? { groups, } : {}),
77
+ ...(userProfile !== undefined ? { userProfile, } : {}),
78
+ };
79
+ }
52
80
  export function permissionStatusForError(error) {
53
81
  if (error instanceof DataikuError) {
54
82
  if (error.status === 401 || error.status === 403 || error.status === 404)
@@ -261,6 +289,7 @@ export async function runDoctor(flags) {
261
289
  });
262
290
  let accessibleProjects;
263
291
  let environmentVersion;
292
+ let identity;
264
293
  if (credentialsOk) {
265
294
  const requestTimeoutMs = num(flags["request-timeout"], "--request-timeout");
266
295
  const retryMaxAttempts = num(flags["retries"], "--retries");
@@ -318,6 +347,12 @@ export async function runDoctor(flags) {
318
347
  details: errorDetails(error),
319
348
  });
320
349
  }
350
+ // Which principal the key acts as (personal vs global key, groups) explains
351
+ // 403s on objects the user's UI profile can use. Diagnostic only: an
352
+ // unanswered /auth/info (older DSS) never fails doctor.
353
+ if (accessibleProjects) {
354
+ identity = await client.get("/public/api/auth/info").then(doctorIdentityFromAuthInfo, () => undefined);
355
+ }
321
356
  if (projectKey) {
322
357
  try {
323
358
  const project = await client.projects.get(projectKey);
@@ -341,7 +376,12 @@ export async function runDoctor(flags) {
341
376
  }
342
377
  }
343
378
  }
344
- const result = { ok: checks.every((check) => check.ok), checks, context, };
379
+ const result = {
380
+ ok: checks.every((check) => check.ok),
381
+ checks,
382
+ context,
383
+ ...(identity ? { identity, } : {}),
384
+ };
345
385
  if (flags["capabilities"] === true && credentialsOk) {
346
386
  const requestTimeoutMs = num(flags["request-timeout"], "--request-timeout");
347
387
  const retryMaxAttempts = num(flags["retries"], "--retries") ?? 1;
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Positional arguments scanned with the same flag grammar as `parseArgs`, so
3
+ * error reporting can recover the invoked resource/action without depending
4
+ * on the command registry being loaded.
5
+ */
6
+ export declare function rawPositionals(argv: string[]): string[];
1
7
  /** Planning wins dispatch; dryRun remains set for combined plan metadata. */
2
8
  export declare function executionMode(flags: Record<string, string | boolean>): {
3
9
  readonly plan: boolean;
@@ -10,7 +16,7 @@ export declare const FLAG_ALIASES: Record<string, string>;
10
16
  export declare const VALUE_FLAGS: Set<string>;
11
17
  export declare const REPEATABLE_VALUE_FLAGS: Set<string>;
12
18
  export declare const KNOWN_LONG_FLAGS: Set<string>;
13
- export declare function normalizeLongFlag(rawFlagName: string): string;
19
+ export declare function normalizeLongFlag(rawFlagName: string, argv: string[]): string;
14
20
  export declare function isNegativeNumberToken(value: string): boolean;
15
21
  export declare function requireFlagValue(flagLabel: string, next: string | undefined): string;
16
22
  export declare function setParsedFlagValue(flags: Record<string, string | boolean>, flagName: string, value: string): void;
@@ -1,5 +1,40 @@
1
1
  import { parseBooleanOption, } from "./coerce.js";
2
- import { unsupportedHelpFlag, UsageError, } from "./usage.js";
2
+ import { unknownFlagError, unsupportedHelpFlag, UsageError, } from "./usage.js";
3
+ /**
4
+ * Positional arguments scanned with the same flag grammar as `parseArgs`, so
5
+ * error reporting can recover the invoked resource/action without depending
6
+ * on the command registry being loaded.
7
+ */
8
+ export function rawPositionals(argv) {
9
+ const positionals = [];
10
+ for (let index = 0; index < argv.length; index++) {
11
+ const arg = argv[index];
12
+ if (arg === "--") {
13
+ positionals.push(...argv.slice(index + 1));
14
+ break;
15
+ }
16
+ if (arg.startsWith("--")) {
17
+ const name = arg.slice(2).split("=")[0] ?? "";
18
+ const canonical = FLAG_ALIASES[name] ?? name;
19
+ if (!arg.includes("=") && VALUE_FLAGS.has(canonical))
20
+ index++;
21
+ continue;
22
+ }
23
+ if (arg.length === 2 && arg[0] === "-" && arg[1] !== "-") {
24
+ const long = SHORT_FLAGS[arg[1]];
25
+ if (long && VALUE_FLAGS.has(long))
26
+ index++;
27
+ continue;
28
+ }
29
+ positionals.push(arg);
30
+ }
31
+ return positionals;
32
+ }
33
+ /** Unknown flags name the invoked command, so the error carries its usage line. */
34
+ function commandUnknownFlagError(flagLabel, argv) {
35
+ const [resource, action,] = rawPositionals(argv);
36
+ return unknownFlagError(flagLabel, resource, action);
37
+ }
3
38
  /** Planning wins dispatch; dryRun remains set for combined plan metadata. */
4
39
  export function executionMode(flags) {
5
40
  return {
@@ -31,11 +66,17 @@ export const BOOLEAN_FLAGS = new Set([
31
66
  "if-exists",
32
67
  "no-wait",
33
68
  "force-rebuild",
69
+ "auto-update-schema",
34
70
  "latest",
71
+ "full",
35
72
  "copy-output-settings",
36
73
  "copy-permissions",
37
74
  "continue-on-error",
38
75
  "no-backup",
76
+ "no-auto-rebuild",
77
+ "all-users",
78
+ "with-scenarios",
79
+ "for-everybody",
39
80
  "payload-only",
40
81
  "allow-same-path",
41
82
  "sync",
@@ -249,6 +290,37 @@ export const VALUE_FLAGS = new Set([
249
290
  "full-class-name",
250
291
  "include-libs",
251
292
  "archive",
293
+ "stop-at",
294
+ "mark-ok",
295
+ "template-file",
296
+ "group-by",
297
+ "aggregate",
298
+ "order-by",
299
+ "rename",
300
+ "fill-empty",
301
+ "formula",
302
+ "filter",
303
+ "drop-columns",
304
+ "keep-columns",
305
+ "columns",
306
+ "format-option",
307
+ "bundle-id",
308
+ "archive-path",
309
+ "project-folder",
310
+ "classes",
311
+ "version-id",
312
+ "evaluation-dataset",
313
+ "experiments",
314
+ "view-type",
315
+ "format",
316
+ "kind",
317
+ "features",
318
+ "sample-size",
319
+ "random-state",
320
+ "n-jobs",
321
+ "time-variable",
322
+ "timeseries-ids",
323
+ "full-reguess",
252
324
  ]);
253
325
  export const REPEATABLE_VALUE_FLAGS = new Set([
254
326
  "dataset",
@@ -269,12 +341,12 @@ export const KNOWN_LONG_FLAGS = new Set([
269
341
  ...Object.keys(FLAG_ALIASES),
270
342
  ...Object.values(FLAG_ALIASES),
271
343
  ]);
272
- export function normalizeLongFlag(rawFlagName) {
344
+ export function normalizeLongFlag(rawFlagName, argv) {
273
345
  if (rawFlagName === "help")
274
346
  throw unsupportedHelpFlag();
275
347
  const flagName = FLAG_ALIASES[rawFlagName] ?? rawFlagName;
276
348
  if (!KNOWN_LONG_FLAGS.has(rawFlagName) && !KNOWN_LONG_FLAGS.has(flagName)) {
277
- throw new UsageError(`Unknown flag: --${rawFlagName}`, "unknown_flag");
349
+ throw commandUnknownFlagError(`--${rawFlagName}`, argv);
278
350
  }
279
351
  return flagName;
280
352
  }
@@ -309,7 +381,7 @@ export function parseArgs(argv) {
309
381
  const eqIdx = arg.indexOf("=");
310
382
  if (eqIdx !== -1) {
311
383
  const raw = arg.slice(2, eqIdx);
312
- const flagName = normalizeLongFlag(raw);
384
+ const flagName = normalizeLongFlag(raw, argv);
313
385
  const value = arg.slice(eqIdx + 1);
314
386
  if (BOOLEAN_FLAGS.has(flagName)) {
315
387
  flags[flagName] = parseBooleanOption(value, `--${flagName}`);
@@ -320,7 +392,7 @@ export function parseArgs(argv) {
320
392
  }
321
393
  else {
322
394
  const rawFlagName = arg.slice(2);
323
- const flagName = normalizeLongFlag(rawFlagName);
395
+ const flagName = normalizeLongFlag(rawFlagName, argv);
324
396
  if (BOOLEAN_FLAGS.has(flagName)) {
325
397
  flags[flagName] = true;
326
398
  }
@@ -346,7 +418,7 @@ export function parseArgs(argv) {
346
418
  else {
347
419
  if (arg[1] === "h")
348
420
  throw unsupportedHelpFlag();
349
- throw new UsageError(`Unknown flag: -${arg[1]}`, "unknown_flag");
421
+ throw commandUnknownFlagError(`-${arg[1]}`, argv);
350
422
  }
351
423
  }
352
424
  else {
@@ -1,4 +1,3 @@
1
- import { randomUUID, } from "node:crypto";
2
1
  import { DataikuError, } from "../../errors.js";
3
2
  import { projectIncarnationHash, } from "../../utils/project-incarnation.js";
4
3
  import { stableHash, stringField, } from "../coerce.js";
@@ -26,7 +25,7 @@ export const VISUAL_UI_GATE = {
26
25
  * probed for absence and is never retried under an alternate key.
27
26
  */
28
27
  export function generatedInstanceKey() {
29
- return `APP_${randomUUID().replace(/-/g, "").toUpperCase()}`;
28
+ return `APP_${crypto.randomUUID().replace(/-/g, "").toUpperCase()}`;
30
29
  }
31
30
  /**
32
31
  * DSS answers the app-manifest probe with 400 ("neither an app template nor an
@@ -0,0 +1,21 @@
1
+ import type { DataikuClient } from "../../client.js";
2
+ import type { DocumentationTemplate } from "../../resources/documentation.js";
3
+ import type { DssTask, FutureWaitOptions } from "../../resources/futures.js";
4
+ import type { FutureWaitResult } from "../../schemas.js";
5
+ type Flags = Record<string, string | boolean>;
6
+ /** Documentation template from flags: --template-file, or --folder with --path, or the DSS default. */
7
+ export declare function documentationTemplateFromFlags(flags: Flags): DocumentationTemplate;
8
+ /** `--poll-interval` / `--timeout` for commands that wait on a DSS task. */
9
+ export declare function taskWaitOptions(flags: Flags): FutureWaitOptions;
10
+ /**
11
+ * Shared `generate-documentation` flow: return the started task; with
12
+ * --wait, its final state; with --output PATH, wait and download the docx
13
+ * named by the result's `exportId`. A failed or timed-out generation carries
14
+ * no exportId, so its state is returned instead.
15
+ */
16
+ export declare function runDocumentationCommand(client: DataikuClient, flags: Flags, task: DssTask, download: (exportId: string) => Promise<Response>): Promise<DssTask | FutureWaitResult | {
17
+ path: string;
18
+ bytes: number;
19
+ exportId: string;
20
+ }>;
21
+ export {};
@@ -0,0 +1,53 @@
1
+ import { writeResponseToFile, } from "../../utils/response-file.js";
2
+ import { num, } from "../coerce.js";
3
+ import { UsageError, } from "../usage.js";
4
+ /** Documentation template from flags: --template-file, or --folder with --path, or the DSS default. */
5
+ export function documentationTemplateFromFlags(flags) {
6
+ const file = flags["template-file"];
7
+ const folder = flags["folder"];
8
+ const path = flags["path"];
9
+ if (typeof file === "string" && (folder !== undefined || path !== undefined)) {
10
+ throw new UsageError("Use either --template-file or --folder with --path, not both.", "conflicting_input_sources");
11
+ }
12
+ if (typeof file === "string")
13
+ return { kind: "file", filePath: file, };
14
+ if (typeof folder === "string" || typeof path === "string") {
15
+ if (typeof folder !== "string" || typeof path !== "string") {
16
+ throw new UsageError("A template in a managed folder needs both --folder FOLDER_ID and --path PATH.", "missing_required_flag");
17
+ }
18
+ return { kind: "folder", folderId: folder, path, };
19
+ }
20
+ return { kind: "default", };
21
+ }
22
+ /** `--poll-interval` / `--timeout` for commands that wait on a DSS task. */
23
+ export function taskWaitOptions(flags) {
24
+ return {
25
+ pollIntervalMs: num(flags["poll-interval"], "--poll-interval"),
26
+ timeoutMs: num(flags["timeout"], "--timeout"),
27
+ };
28
+ }
29
+ /**
30
+ * Shared `generate-documentation` flow: return the started task; with
31
+ * --wait, its final state; with --output PATH, wait and download the docx
32
+ * named by the result's `exportId`. A failed or timed-out generation carries
33
+ * no exportId, so its state is returned instead.
34
+ */
35
+ export async function runDocumentationCommand(client, flags, task, download) {
36
+ const output = flags["output"];
37
+ if (flags["wait"] !== true && typeof output !== "string")
38
+ return task;
39
+ const waited = await client.futures.waitTask(task, taskWaitOptions(flags));
40
+ if (typeof output !== "string")
41
+ return waited;
42
+ const result = waited.result;
43
+ const exportId = result && typeof result === "object" && "exportId" in result
44
+ ? result.exportId
45
+ : undefined;
46
+ if (typeof exportId !== "string")
47
+ return waited;
48
+ return {
49
+ path: output,
50
+ bytes: await writeResponseToFile(output, await download(exportId)),
51
+ exportId,
52
+ };
53
+ }
@@ -0,0 +1,26 @@
1
+ import type { DataikuClient } from "../../client.js";
2
+ import { type ComputedModelDiagnostic, type ModelDiagnostic, type ModelDiagnosticsComputation, type TrainedModel } from "../../resources/trained-model.js";
3
+ import type { CommandDefinition } from "../types.js";
4
+ type Flags = Record<string, string | boolean>;
5
+ export declare function diagnosticKindFromFlags(flags: Flags): ModelDiagnostic;
6
+ /** `compute-diagnostics` flags → kind, features, and computation settings (shared with --plan). */
7
+ export declare function diagnosticsComputationFromFlags(flags: Flags): {
8
+ kind: ComputedModelDiagnostic;
9
+ features: string[];
10
+ computation: ModelDiagnosticsComputation;
11
+ };
12
+ export interface TrainedModelCommandSpec {
13
+ resource: "ml-task" | "saved-model";
14
+ /** Positional ids in examples, e.g. `ANALYSIS_ID TASK_ID MODEL_ID`. */
15
+ ids: string;
16
+ /** What one model is called in descriptions: "lab model" or "saved-model version". */
17
+ noun: string;
18
+ model: (client: DataikuClient, args: string[], projectKey: string | undefined) => TrainedModel;
19
+ downloadDocumentation: (client: DataikuClient, exportId: string, projectKey: string | undefined) => Promise<Response>;
20
+ }
21
+ /**
22
+ * The actions lab models and saved-model versions share, over one
23
+ * {@link TrainedModel}: user meta, scoring exports, diagnostics, documentation.
24
+ */
25
+ export declare function trainedModelCommands(spec: TrainedModelCommandSpec): Record<string, CommandDefinition>;
26
+ export {};
@@ -0,0 +1,144 @@
1
+ import { unexpectedResponseError, } from "../../errors.js";
2
+ import { COMPUTED_MODEL_DIAGNOSTICS, MODEL_DIAGNOSTICS, } from "../../resources/trained-model.js";
3
+ import { writeResponseToFile, } from "../../utils/response-file.js";
4
+ import { num, parseBooleanOption, requiredJsonInput, splitCsvFlag, } from "../coerce.js";
5
+ import { executionMode, } from "../flags.js";
6
+ import { commandUsage, } from "../syntax.js";
7
+ import { requireArgs, UsageError, } from "../usage.js";
8
+ import { documentationTemplateFromFlags, runDocumentationCommand, taskWaitOptions, } from "./documentation.js";
9
+ export function diagnosticKindFromFlags(flags) {
10
+ const kind = flags["kind"];
11
+ if (typeof kind !== "string" || MODEL_DIAGNOSTICS[kind] !== true) {
12
+ throw new UsageError(`--kind must be one of ${Object.keys(MODEL_DIAGNOSTICS).join(", ")}.`, "invalid_enum");
13
+ }
14
+ return kind;
15
+ }
16
+ /** `compute-diagnostics` flags → kind, features, and computation settings (shared with --plan). */
17
+ export function diagnosticsComputationFromFlags(flags) {
18
+ const kind = flags["kind"];
19
+ if (typeof kind !== "string" || COMPUTED_MODEL_DIAGNOSTICS[kind] !== true) {
20
+ throw new UsageError(`--kind must be one of ${Object.keys(COMPUTED_MODEL_DIAGNOSTICS).join(", ")}.`, "invalid_enum");
21
+ }
22
+ const sampleSize = num(flags["sample-size"], "--sample-size");
23
+ const randomState = num(flags["random-state"], "--random-state");
24
+ const nJobs = num(flags["n-jobs"], "--n-jobs");
25
+ return {
26
+ kind: kind,
27
+ features: splitCsvFlag(flags["features"]),
28
+ computation: {
29
+ ...(sampleSize !== undefined ? { sampleSize, } : {}),
30
+ ...(randomState !== undefined ? { randomState, } : {}),
31
+ ...(nJobs !== undefined ? { nJobs, } : {}),
32
+ },
33
+ };
34
+ }
35
+ /** Write a binary export to `--output`; DSS answering without a body is an unexpected response. */
36
+ async function writeExport(res, out, operation) {
37
+ if (!res.body)
38
+ throw unexpectedResponseError(`${operation} response did not include a body`);
39
+ return { path: out, bytes: await writeResponseToFile(out, res), };
40
+ }
41
+ function requiredOutput(flags) {
42
+ const out = flags["output"];
43
+ if (typeof out !== "string") {
44
+ throw new UsageError("--output PATH is required.", "missing_required_flag");
45
+ }
46
+ return out;
47
+ }
48
+ /**
49
+ * The actions lab models and saved-model versions share, over one
50
+ * {@link TrainedModel}: user meta, scoring exports, diagnostics, documentation.
51
+ */
52
+ export function trainedModelCommands(spec) {
53
+ const { resource, ids, noun, } = spec;
54
+ const argCount = ids.split(" ").length;
55
+ const model = (c, a, f, action) => {
56
+ requireArgs(a, argCount, commandUsage(resource, action));
57
+ return spec.model(c, a, f["project-key"]);
58
+ };
59
+ return {
60
+ "set-user-meta": {
61
+ handler: async (c, a, f) => {
62
+ const target = model(c, a, f, "set-user-meta");
63
+ const userMeta = requiredJsonInput(f, "User-meta JSON is required via --data, --data-file, or --stdin.");
64
+ if (executionMode(f).dryRun) {
65
+ return {
66
+ dryRun: true,
67
+ action: "set-user-meta",
68
+ resource,
69
+ ids: a.slice(0, argCount),
70
+ payload: userMeta,
71
+ };
72
+ }
73
+ await target.setUserMeta(userMeta);
74
+ return { updated: a[argCount - 1], resource, };
75
+ },
76
+ description: `Update the user metadata (name, description, labels, ...) of a ${noun}. Send only the "userMeta" field of its details, edited.`,
77
+ examples: [
78
+ `dss ${resource} set-user-meta ${ids} --data '{"name":"Churn model","description":"v2"}'`,
79
+ ],
80
+ },
81
+ "download-scoring-jar": {
82
+ handler: async (c, a, f) => {
83
+ const target = model(c, a, f, "download-scoring-jar");
84
+ const out = requiredOutput(f);
85
+ const fullClassName = f["full-class-name"];
86
+ const res = await target.downloadScoringJar({
87
+ ...(typeof fullClassName === "string" ? { fullClassName, } : {}),
88
+ ...(f["include-libs"] !== undefined
89
+ ? { includeLibs: parseBooleanOption(f["include-libs"], "--include-libs"), }
90
+ : {}),
91
+ });
92
+ return writeExport(res, out, "Scoring JAR download");
93
+ },
94
+ description: `Download the optimized scoring JAR of a ${noun} (license-gated server side). --full-class-name sets the Java class; --include-libs toggles bundling the scoring libraries.`,
95
+ examples: [`dss ${resource} download-scoring-jar ${ids} --output ./scoring.jar`,],
96
+ },
97
+ "download-scoring-pmml": {
98
+ handler: async (c, a, f) => {
99
+ const target = model(c, a, f, "download-scoring-pmml");
100
+ const out = requiredOutput(f);
101
+ return writeExport(await target.downloadScoringPmml(), out, "Scoring PMML download");
102
+ },
103
+ description: `Download the PMML scoring file of a ${noun} (license-gated server side).`,
104
+ examples: [`dss ${resource} download-scoring-pmml ${ids} --output ./model.pmml`,],
105
+ },
106
+ diagnostics: {
107
+ handler: (c, a, f) => model(c, a, f, "diagnostics").get(diagnosticKindFromFlags(f)),
108
+ description: `Read computed diagnostics of a ${noun}: subpopulation-analyses, partial-dependencies, timeseries-residuals, or (forecasting) per-timeseries-metrics / per-timeseries-evaluation-forecasts.`,
109
+ examples: [`dss ${resource} diagnostics ${ids} --kind partial-dependencies`,],
110
+ },
111
+ "compute-diagnostics": {
112
+ handler: async (c, a, f) => {
113
+ const target = model(c, a, f, "compute-diagnostics");
114
+ const { kind, features, computation, } = diagnosticsComputationFromFlags(f);
115
+ const task = await target.compute(kind, features, computation);
116
+ return f["wait"] === true ? c.futures.waitTask(task, taskWaitOptions(f)) : task;
117
+ },
118
+ description: `Compute subpopulation-analyses or partial-dependencies over --features COLS (--sample-size N, default 10000), or timeseries-residuals, for a ${noun}. Returns the DSS future; --wait waits and returns the result.`,
119
+ examples: [
120
+ `dss ${resource} compute-diagnostics ${ids} --kind partial-dependencies --features age,income --wait`,
121
+ ],
122
+ },
123
+ "generate-documentation": {
124
+ handler: async (c, a, f) => {
125
+ const target = model(c, a, f, "generate-documentation");
126
+ const pk = f["project-key"];
127
+ const task = await target.generateDocumentation(documentationTemplateFromFlags(f));
128
+ return runDocumentationCommand(c, f, task, (exportId) => spec.downloadDocumentation(c, exportId, pk));
129
+ },
130
+ description: `Generate the model documentation (Word docx) of a ${noun} from the DSS default template, an uploaded --template-file, or a template in a managed folder (--folder FOLDER_ID --path PATH). Returns the DSS future; --wait waits; --output PATH waits and downloads.`,
131
+ examples: [`dss ${resource} generate-documentation ${ids} --output model.docx`,],
132
+ },
133
+ "download-documentation": {
134
+ handler: async (c, a, f) => {
135
+ requireArgs(a, 1, commandUsage(resource, "download-documentation"));
136
+ const out = requiredOutput(f);
137
+ const res = await spec.downloadDocumentation(c, a[0], f["project-key"]);
138
+ return writeExport(res, out, "Model documentation download");
139
+ },
140
+ description: "Download a generated model documentation by the exportId from a finished generate-documentation future.",
141
+ examples: [`dss ${resource} download-documentation EXPORT_ID --output model.docx`,],
142
+ },
143
+ };
144
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Shape a `*.list` result for agents: `--contains` filters on identifier
3
+ * fields, `--limit` caps the count (a `list_truncated` warning reports the
4
+ * total), and large DSS objects compact to their decision fields unless
5
+ * `--full` or `--fields` asks for the DSS objects.
6
+ */
7
+ export declare function shapeListResult(resource: string, result: unknown, flags: Record<string, string | boolean>): unknown;
@@ -0,0 +1,77 @@
1
+ import { num, } from "./coerce.js";
2
+ import { COMPACT_LIST_FIELDS, } from "./list-shapes.js";
3
+ import { enqueueCliWarning, } from "./output.js";
4
+ function record(value) {
5
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
6
+ }
7
+ function compactValue(item, spec) {
8
+ let value = item;
9
+ for (const key of spec.path.split("."))
10
+ value = record(value)[key];
11
+ if (spec.roleRefs !== true)
12
+ return value;
13
+ // Dataset refs across every role of recipe inputs/outputs (`{main:{items:[{ref}]}}`).
14
+ return Object.values(record(value)).flatMap((role) => {
15
+ const items = record(role).items;
16
+ return Array.isArray(items)
17
+ ? items.flatMap((entry) => {
18
+ const ref = record(entry).ref;
19
+ return typeof ref === "string" ? [ref,] : [];
20
+ })
21
+ : [];
22
+ });
23
+ }
24
+ /** Identifier fields `--contains` matches; string items match themselves. */
25
+ const IDENTIFIER_FIELDS = [
26
+ "id",
27
+ "name",
28
+ "projectKey",
29
+ "envName",
30
+ "login",
31
+ "displayName",
32
+ "label",
33
+ "runnableType",
34
+ ];
35
+ /** `job list` filters by --contains/--limit itself (job name, state, outputs). */
36
+ const LISTS_WITH_OWN_FILTERS = { job: true, };
37
+ function itemMatches(item, needle) {
38
+ if (typeof item === "string")
39
+ return item.toLowerCase().includes(needle);
40
+ const fields = record(item);
41
+ return IDENTIFIER_FIELDS.some((field) => {
42
+ const value = fields[field];
43
+ return typeof value === "string" && value.toLowerCase().includes(needle);
44
+ });
45
+ }
46
+ /**
47
+ * Shape a `*.list` result for agents: `--contains` filters on identifier
48
+ * fields, `--limit` caps the count (a `list_truncated` warning reports the
49
+ * total), and large DSS objects compact to their decision fields unless
50
+ * `--full` or `--fields` asks for the DSS objects.
51
+ */
52
+ export function shapeListResult(resource, result, flags) {
53
+ if (!Array.isArray(result))
54
+ return result;
55
+ let items = result;
56
+ if (LISTS_WITH_OWN_FILTERS[resource] !== true) {
57
+ const contains = flags["contains"];
58
+ if (typeof contains === "string" && contains.length > 0) {
59
+ const needle = contains.toLowerCase();
60
+ items = items.filter((item) => itemMatches(item, needle));
61
+ }
62
+ const limit = num(flags["limit"], "--limit");
63
+ if (limit !== undefined && items.length > limit) {
64
+ enqueueCliWarning({
65
+ code: "list_truncated",
66
+ shown: limit,
67
+ total: items.length,
68
+ hint: "Raise --limit or narrow with --contains.",
69
+ });
70
+ items = items.slice(0, Math.max(0, limit));
71
+ }
72
+ }
73
+ const fields = COMPACT_LIST_FIELDS[resource];
74
+ if (!fields || flags["full"] === true || typeof flags["fields"] === "string")
75
+ return items;
76
+ return items.map((item) => Object.fromEntries(Object.entries(fields).map(([name, spec,]) => [name, compactValue(record(item), spec),])));
77
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Compact `RESOURCE.list` item shapes, as plain data shared by the runtime
3
+ * mapper (src/cli/list-output.ts) and the discovery output schemas
4
+ * (src/cli/output-schemas.ts), so the advertised schema is the emitted shape.
5
+ */
6
+ /** Where a compact field comes from in the DSS object, and its JSON Schema. */
7
+ export interface CompactListField {
8
+ /** Dotted path into the DSS list item. */
9
+ path: string;
10
+ /** Flatten recipe roles (`{main:{items:[{ref}]}}`) to the dataset refs. */
11
+ roleRefs?: true;
12
+ schema: Record<string, unknown>;
13
+ }
14
+ /**
15
+ * Lists whose DSS objects are large: the identifier the follow-up get/build
16
+ * commands take, the kind, and the one or two attributes that decide what to
17
+ * call next. Lists not named here keep the DSS objects.
18
+ */
19
+ export declare const COMPACT_LIST_FIELDS: Record<string, Record<string, CompactListField>>;
20
+ /** Discovery output schemas of the compact `RESOURCE.list` defaults. */
21
+ export declare function compactListOutputSchemas(): Record<string, Record<string, unknown>>;