tripo-cli 0.7.3 → 0.8.1
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/CHANGELOG.md +33 -0
- package/README.md +10 -7
- package/dist/ai/experts.js +25 -19
- package/dist/ai/plan-card.js +71 -33
- package/dist/ai/wizard.js +13 -17
- package/dist/commands/account.js +2 -6
- package/dist/commands/ai.js +18 -16
- package/dist/commands/batch.js +58 -18
- package/dist/commands/completion.js +1 -1
- package/dist/commands/config-cmd.js +1 -1
- package/dist/commands/doctor.js +1 -3
- package/dist/commands/generate.js +35 -4
- package/dist/commands/home.js +12 -13
- package/dist/commands/login.js +72 -187
- package/dist/commands/make.js +47 -25
- package/dist/commands/mcp.js +2 -1
- package/dist/commands/models.js +47 -0
- package/dist/commands/process-groups.js +3 -4
- package/dist/commands/shared.js +9 -14
- package/dist/commands/task.js +10 -11
- package/dist/commands/topup.js +6 -10
- package/dist/commands/update.js +6 -10
- package/dist/commands/view.js +3 -4
- package/dist/config/config.js +1 -1
- package/dist/core/client.js +4 -13
- package/dist/core/errors.js +16 -11
- package/dist/core/output.js +0 -4
- package/dist/core/requests.js +61 -17
- package/dist/core/task-service.js +19 -20
- package/dist/knowledge/chains.js +12 -12
- package/dist/knowledge/error-catalog.js +32 -32
- package/dist/knowledge/models.js +119 -20
- package/dist/knowledge/params.js +96 -8
- package/dist/knowledge/scenarios.js +32 -55
- package/dist/pipeline/make.js +36 -28
- package/dist/pipeline/runner.js +7 -12
- package/dist/pipeline/stdin.js +40 -3
- package/dist/program.js +6 -11
- package/package.json +3 -2
- package/skill/SKILL.md +35 -8
- package/skill/commands/account.md +1 -1
- package/skill/commands/batch.md +13 -3
- package/skill/commands/generate.md +35 -10
- package/skill/commands/make.md +39 -13
- package/skill/commands/process.md +2 -1
- package/skill/commands/task.md +2 -2
- package/skill/commands/view.md +1 -1
- package/skill/common-errors.md +6 -3
- package/skill/examples/animation.md +3 -1
- package/skill/examples/ar-web.md +6 -4
- package/skill/examples/game-asset.md +17 -6
- package/skill/examples/pipes.md +2 -2
- package/skill/examples/print.md +7 -3
- package/dist/i18n.js +0 -19
package/dist/core/errors.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/** CLI error types carrying stable exit codes and human translations. */
|
|
2
|
-
import { t } from '../i18n.js';
|
|
3
2
|
import { EXIT, exitCodeFor, isRetryable, lookupError } from '../knowledge/error-catalog.js';
|
|
4
3
|
export class CliError extends Error {
|
|
5
4
|
exitCode;
|
|
6
5
|
suggestion;
|
|
6
|
+
/** A create request failed without a response: the paid task may exist server-side. */
|
|
7
|
+
submissionUncertain;
|
|
7
8
|
constructor(message, exitCode = EXIT.FATAL, suggestion) {
|
|
8
9
|
super(message);
|
|
9
10
|
this.exitCode = exitCode;
|
|
@@ -17,7 +18,7 @@ export class UsageError extends CliError {
|
|
|
17
18
|
}
|
|
18
19
|
export class AuthError extends CliError {
|
|
19
20
|
constructor(message, suggestion) {
|
|
20
|
-
super(message, EXIT.AUTH, suggestion ??
|
|
21
|
+
super(message, EXIT.AUTH, suggestion ?? 'run "tripo login" to configure an API key');
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
export class ApiError extends CliError {
|
|
@@ -31,7 +32,7 @@ export class ApiError extends CliError {
|
|
|
31
32
|
// HTTP 401 reads as an auth failure whatever code the body carries (see error-catalog).
|
|
32
33
|
const code = opts.httpStatus === 401 ? 1002 : opts.apiCode;
|
|
33
34
|
const info = code !== undefined ? lookupError(code) : undefined;
|
|
34
|
-
const translated = info
|
|
35
|
+
const translated = info?.message;
|
|
35
36
|
const parts = [translated ?? opts.message ?? `API error (HTTP ${opts.httpStatus})`];
|
|
36
37
|
if (translated && opts.message && opts.message !== translated)
|
|
37
38
|
parts.push(`(${opts.message})`);
|
|
@@ -48,14 +49,21 @@ export class NetworkError extends CliError {
|
|
|
48
49
|
super(message, EXIT.NETWORK, suggestion);
|
|
49
50
|
}
|
|
50
51
|
}
|
|
52
|
+
/** The task succeeded (and was billed); only fetching its artifacts failed. */
|
|
53
|
+
export class ArtifactDownloadError extends NetworkError {
|
|
54
|
+
taskId;
|
|
55
|
+
result;
|
|
56
|
+
constructor(taskId, result, reason) {
|
|
57
|
+
super(`task ${taskId} succeeded but downloading its artifacts failed: ${reason}`, `the task is finished and billed; do not regenerate. Download it with "tripo task get ${taskId} --download"`);
|
|
58
|
+
this.taskId = taskId;
|
|
59
|
+
this.result = result;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
51
62
|
export class TaskFailedError extends CliError {
|
|
52
63
|
taskId;
|
|
53
64
|
status;
|
|
54
65
|
constructor(taskId, status, detail) {
|
|
55
|
-
const refundNote =
|
|
56
|
-
zh: '预扣积分已自动退还',
|
|
57
|
-
en: 'frozen credits have been refunded automatically',
|
|
58
|
-
});
|
|
66
|
+
const refundNote = 'frozen credits have been refunded automatically';
|
|
59
67
|
super(
|
|
60
68
|
// Only failed/cancelled tasks are refunded; a timed-out task is still running server-side.
|
|
61
69
|
`task ${taskId} ${status}${detail ? `: ${detail}` : ''}${status === 'failed' || status === 'cancelled' ? ` (${refundNote})` : ''}`, EXIT.TASK_FAILED);
|
|
@@ -66,8 +74,5 @@ export class TaskFailedError extends CliError {
|
|
|
66
74
|
/** Decorate insufficient-balance errors with the topup path and the gap. */
|
|
67
75
|
export function balanceSuggestion(needed, balance) {
|
|
68
76
|
const gap = needed !== undefined && balance !== undefined ? Math.max(0, needed - balance) : undefined;
|
|
69
|
-
return
|
|
70
|
-
zh: `运行 tripo topup 充值${gap !== undefined ? `(还差约 ${gap} 积分)` : ''}`,
|
|
71
|
-
en: `run "tripo topup" to add credits${gap !== undefined ? ` (about ${gap} more needed)` : ''}`,
|
|
72
|
-
});
|
|
77
|
+
return `run "tripo topup" to add credits${gap !== undefined ? ` (about ${gap} more needed)` : ''}`;
|
|
73
78
|
}
|
package/dist/core/output.js
CHANGED
|
@@ -66,7 +66,3 @@ export function emitResult(data, human) {
|
|
|
66
66
|
process.stdout.write((human ?? JSON.stringify(data, null, 2)) + '\n');
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
-
/** Stream one NDJSON event to stdout (used by watch-style streaming output). */
|
|
70
|
-
export function emitNdjson(event) {
|
|
71
|
-
process.stdout.write(JSON.stringify(event) + '\n');
|
|
72
|
-
}
|
package/dist/core/requests.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* `parameters`), so new API options work without a CLI release.
|
|
6
6
|
*/
|
|
7
7
|
import { getStep } from '../knowledge/chains.js';
|
|
8
|
-
import { applyTextureV35, validateConvertParams, validateDecimateParams, validateGenerationParams, validateMeshEditParams, validateRetargetParams, } from '../knowledge/params.js';
|
|
9
|
-
import { CAPABILITY_DEFAULTS, SEGMENT_MODELS, TEXTURE_MODELS, normalizeModel, normalizeRigModel, } from '../knowledge/models.js';
|
|
8
|
+
import { applyTextureV35, validateConvertParams, validateDecimateParams, validateGenerationParams, validateImageParams, validateMeshEditParams, validateRetargetParams, } from '../knowledge/params.js';
|
|
9
|
+
import { CAPABILITY_DEFAULTS, RIG_MODEL_V1, RIG_MODEL_V25, RIG_MODEL_V30, RIG_SPECS, RIG_TYPES, SEGMENT_MODELS, TEXTURE_MODELS, normalizeModel, normalizeRigModel, } from '../knowledge/models.js';
|
|
10
10
|
import { UsageError } from './errors.js';
|
|
11
11
|
function ensure(result) {
|
|
12
12
|
if (result.errors.length > 0) {
|
|
@@ -15,12 +15,12 @@ function ensure(result) {
|
|
|
15
15
|
}
|
|
16
16
|
/** 3D generation: text-to-model. */
|
|
17
17
|
export function buildTextToModel(prompt, model, params) {
|
|
18
|
-
const validated = validateGenerationParams(model, params);
|
|
18
|
+
const validated = validateGenerationParams(model, { prompt, ...params });
|
|
19
19
|
ensure(validated);
|
|
20
20
|
return {
|
|
21
21
|
request: {
|
|
22
22
|
endpoint: '/v3/generation/text-to-model',
|
|
23
|
-
payload: { prompt, model: normalizeModel(model)
|
|
23
|
+
payload: { prompt, ...validated.params, model: normalizeModel(model) },
|
|
24
24
|
},
|
|
25
25
|
taskType: 'text_to_model',
|
|
26
26
|
warnings: validated.warnings,
|
|
@@ -33,7 +33,7 @@ export function buildImageToModel(input, model, params) {
|
|
|
33
33
|
return {
|
|
34
34
|
request: {
|
|
35
35
|
endpoint: '/v3/generation/image-to-model',
|
|
36
|
-
payload: { input, model: normalizeModel(model)
|
|
36
|
+
payload: { input, ...validated.params, model: normalizeModel(model) },
|
|
37
37
|
},
|
|
38
38
|
taskType: 'image_to_model',
|
|
39
39
|
warnings: validated.warnings,
|
|
@@ -62,7 +62,7 @@ export function buildMultiviewToModel(views, model, params) {
|
|
|
62
62
|
return {
|
|
63
63
|
request: {
|
|
64
64
|
endpoint: '/v3/generation/multiview-to-model',
|
|
65
|
-
payload: { inputs, model: normalizeModel(model)
|
|
65
|
+
payload: { inputs, ...validated.params, model: normalizeModel(model) },
|
|
66
66
|
},
|
|
67
67
|
taskType: 'multiview_to_model',
|
|
68
68
|
warnings: validated.warnings,
|
|
@@ -72,28 +72,38 @@ export function buildMultiviewToModel(views, model, params) {
|
|
|
72
72
|
* Server task types (TaskType enum): text-to-image → `text_to_image`,
|
|
73
73
|
* image-to-image → `generate_image`. */
|
|
74
74
|
export function buildTextToImage(prompt, params) {
|
|
75
|
+
const validated = validateImageParams(params, false);
|
|
76
|
+
ensure(validated);
|
|
75
77
|
return {
|
|
76
78
|
request: {
|
|
77
79
|
endpoint: '/v3/generation/text-to-image',
|
|
78
|
-
payload: { prompt,
|
|
80
|
+
payload: { prompt, ...validated.params },
|
|
79
81
|
},
|
|
80
82
|
taskType: 'text_to_image',
|
|
81
|
-
warnings:
|
|
83
|
+
warnings: validated.warnings,
|
|
82
84
|
};
|
|
83
85
|
}
|
|
84
86
|
/** One reference image goes as `input`, several as `inputs` (prompt cites them as image[1], image[2], ...). */
|
|
85
87
|
export function buildImageToImage(inputs, params) {
|
|
88
|
+
const validated = validateImageParams(params, true);
|
|
89
|
+
ensure(validated);
|
|
90
|
+
const model = String(validated.params.model);
|
|
91
|
+
const maxInputs = model.startsWith('seedream') ? 4 : model.startsWith('banana') ? 10 : 16;
|
|
92
|
+
if (inputs.length === 0)
|
|
93
|
+
throw new UsageError('image-to-image requires at least one reference image');
|
|
94
|
+
if (inputs.length > maxInputs) {
|
|
95
|
+
throw new UsageError(`${model} accepts at most ${maxInputs} reference images (got ${inputs.length})`);
|
|
96
|
+
}
|
|
86
97
|
return {
|
|
87
98
|
request: {
|
|
88
99
|
endpoint: '/v3/generation/image-to-image',
|
|
89
100
|
payload: {
|
|
90
101
|
...(inputs.length > 1 ? { inputs } : { input: inputs[0] }),
|
|
91
|
-
|
|
92
|
-
...omit(params, ['model']),
|
|
102
|
+
...validated.params,
|
|
93
103
|
},
|
|
94
104
|
},
|
|
95
105
|
taskType: 'generate_image',
|
|
96
|
-
warnings:
|
|
106
|
+
warnings: validated.warnings,
|
|
97
107
|
};
|
|
98
108
|
}
|
|
99
109
|
export function buildImageToMultiview(input, params) {
|
|
@@ -117,6 +127,27 @@ export function buildImageToSplat(input, params) {
|
|
|
117
127
|
warnings: [],
|
|
118
128
|
};
|
|
119
129
|
}
|
|
130
|
+
/** Validate deterministic request and rig/preset constraints before any earlier task runs. */
|
|
131
|
+
export function validateChainRequests(chain) {
|
|
132
|
+
let rigModel;
|
|
133
|
+
for (const spec of chain) {
|
|
134
|
+
const built = buildStepRequest(spec.step, '<upstream>', spec.args);
|
|
135
|
+
if (built.taskType === 'animate_retarget' && rigModel) {
|
|
136
|
+
const { animation, animations } = built.request.payload;
|
|
137
|
+
const requested = Array.isArray(animations) ? animations : [animation];
|
|
138
|
+
for (const preset of requested) {
|
|
139
|
+
if (typeof preset !== 'string' || !preset.startsWith('preset:'))
|
|
140
|
+
continue;
|
|
141
|
+
if ((rigModel === RIG_MODEL_V1) !== preset.startsWith('preset:biped:')) {
|
|
142
|
+
throw new UsageError(`preset ${preset} is incompatible with rig model ${rigModel}; v1.0 uses preset:biped:*, v2.5/v3.0 use generic or body-type presets`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (!getStep(spec.step)?.passthrough) {
|
|
147
|
+
rigModel = built.taskType === 'animate_rig' ? String(built.request.payload.model) : undefined;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
120
151
|
/**
|
|
121
152
|
* Processing step (texture/convert/rig/...): validate per step, then build.
|
|
122
153
|
* `input` must already be a task_id / file_token / URL.
|
|
@@ -161,6 +192,25 @@ export function buildStepRequest(stepName, input, args) {
|
|
|
161
192
|
params.model = params.model === undefined
|
|
162
193
|
? CAPABILITY_DEFAULTS.rig
|
|
163
194
|
: normalizeRigModel(String(params.model));
|
|
195
|
+
if (![RIG_MODEL_V1, RIG_MODEL_V25, RIG_MODEL_V30].includes(String(params.model))) {
|
|
196
|
+
throw new UsageError('unsupported rig model');
|
|
197
|
+
}
|
|
198
|
+
const rigType = params.rig_type === undefined ? 'biped' : params.rig_type;
|
|
199
|
+
if (!RIG_TYPES.includes(rigType))
|
|
200
|
+
throw new UsageError('unsupported rig_type');
|
|
201
|
+
if (params.model === RIG_MODEL_V1 && rigType !== 'biped')
|
|
202
|
+
throw new UsageError('rig v1.0 only supports biped');
|
|
203
|
+
if (rigType === 'others' && params.model !== RIG_MODEL_V30)
|
|
204
|
+
throw new UsageError('rig_type others requires rig v3.0');
|
|
205
|
+
if (params.spec !== undefined) {
|
|
206
|
+
if (!RIG_SPECS.includes(params.spec))
|
|
207
|
+
throw new UsageError('unsupported rig spec');
|
|
208
|
+
if (rigType !== 'biped')
|
|
209
|
+
throw new UsageError('rig spec only applies to biped');
|
|
210
|
+
if (!['tripo', 'mixamo'].includes(String(params.spec)) && params.model !== RIG_MODEL_V30) {
|
|
211
|
+
throw new UsageError('spec actorcore/unity/unreal/vrm requires rig v3.0');
|
|
212
|
+
}
|
|
213
|
+
}
|
|
164
214
|
break;
|
|
165
215
|
}
|
|
166
216
|
case 'texture': {
|
|
@@ -209,9 +259,3 @@ export function buildStepRequest(stepName, input, args) {
|
|
|
209
259
|
warnings,
|
|
210
260
|
};
|
|
211
261
|
}
|
|
212
|
-
function omit(obj, keys) {
|
|
213
|
-
const out = { ...obj };
|
|
214
|
-
for (const k of keys)
|
|
215
|
-
delete out[k];
|
|
216
|
-
return out;
|
|
217
|
-
}
|
|
@@ -8,13 +8,12 @@ import { basename } from 'node:path';
|
|
|
8
8
|
import { resolvePlatformBaseUrl, resolveRegion } from '../config/config.js';
|
|
9
9
|
import { loadContext, updateContext } from '../config/context.js';
|
|
10
10
|
import { RefError, appendHistory, readHistory, resolveReference, slugify, updateHistoryStatus } from '../config/history.js';
|
|
11
|
-
import { t } from '../i18n.js';
|
|
12
11
|
import { detectInput } from '../util/input-detect.js';
|
|
13
12
|
import { notifyDone } from '../util/notify.js';
|
|
14
13
|
import { createSpinner } from '../util/spinner.js';
|
|
15
14
|
import { defaultOutputDir, downloadArtifacts } from './download.js';
|
|
16
15
|
import { taskOrigin } from './analytics.js';
|
|
17
|
-
import { ApiError, CliError, TaskFailedError, UsageError, balanceSuggestion } from './errors.js';
|
|
16
|
+
import { ApiError, ArtifactDownloadError, CliError, TaskFailedError, UsageError, balanceSuggestion } from './errors.js';
|
|
18
17
|
import { isQuiet, log, warn } from './output.js';
|
|
19
18
|
import { uploadLocalFile } from './upload.js';
|
|
20
19
|
/** Placeholder `input` value for a local file that a dry run would upload. */
|
|
@@ -75,10 +74,7 @@ export async function precheckBalance(client) {
|
|
|
75
74
|
throw new ApiError({ apiCode: 2010, suggestion: balanceSuggestion(undefined, balance) });
|
|
76
75
|
}
|
|
77
76
|
if (balance < 30) {
|
|
78
|
-
warn(
|
|
79
|
-
zh: `余额仅剩 ${balance} 积分,任务可能因余额不足失败(tripo topup 充值)`,
|
|
80
|
-
en: `balance is down to ${balance} credits; tasks may fail (run "tripo topup")`,
|
|
81
|
-
}));
|
|
77
|
+
warn(`balance is down to ${balance} credits; tasks may fail (run "tripo topup")`);
|
|
82
78
|
}
|
|
83
79
|
}
|
|
84
80
|
/** Submit one task and (by default) watch it to completion + download. */
|
|
@@ -87,6 +83,8 @@ export async function runTask(options) {
|
|
|
87
83
|
if (options.precheckBalance !== false)
|
|
88
84
|
await precheckBalance(client);
|
|
89
85
|
const taskId = await client.createTask(request.endpoint, request.payload, taskType);
|
|
86
|
+
// Report the task before any local bookkeeping that can throw: batch decides retry safety from it.
|
|
87
|
+
options.onCreated?.({ task_id: taskId, type: taskType });
|
|
90
88
|
const name = uniqueName(slugify(options.name));
|
|
91
89
|
const entry = {
|
|
92
90
|
analytics_origin: taskOrigin(request.payload.model),
|
|
@@ -99,8 +97,13 @@ export async function runTask(options) {
|
|
|
99
97
|
payload: request.payload,
|
|
100
98
|
};
|
|
101
99
|
appendHistory(entry);
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
try {
|
|
101
|
+
updateContext({ last_task_id: taskId });
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
warn(`could not update .tripo/context.json (${err instanceof Error ? err.message : String(err)})`);
|
|
105
|
+
}
|
|
106
|
+
log(`task created ${taskId} (@${name})`);
|
|
104
107
|
if (options.noWait) {
|
|
105
108
|
return { task_id: taskId, type: taskType, status: 'queued' };
|
|
106
109
|
}
|
|
@@ -121,17 +124,14 @@ export async function runTask(options) {
|
|
|
121
124
|
updateHistoryStatus(taskId, 'failed');
|
|
122
125
|
}
|
|
123
126
|
else if (err instanceof CliError) {
|
|
124
|
-
err.suggestion =
|
|
125
|
-
zh: `任务仍在服务端运行,成功后照常扣费;用 tripo task watch ${taskId} --download 继续等待,不要重新提交`,
|
|
126
|
-
en: `the task keeps running server-side and is billed if it succeeds; resume with "tripo task watch ${taskId} --download" instead of resubmitting`,
|
|
127
|
-
});
|
|
127
|
+
err.suggestion = `the task keeps running server-side and is billed if it succeeds; resume with "tripo task watch ${taskId} --download" instead of resubmitting`;
|
|
128
128
|
}
|
|
129
129
|
throw err;
|
|
130
130
|
}
|
|
131
131
|
updateHistoryStatus(taskId, 'success', { credits_consumed: task.credits_consumed });
|
|
132
132
|
spinner.succeed(`${taskType} · ${taskId}` +
|
|
133
133
|
(task.credits_consumed !== undefined
|
|
134
|
-
?
|
|
134
|
+
? ` · ${task.credits_consumed} credits`
|
|
135
135
|
: ''));
|
|
136
136
|
const result = {
|
|
137
137
|
task_id: taskId,
|
|
@@ -144,12 +144,12 @@ export async function runTask(options) {
|
|
|
144
144
|
if (!options.noDownload) {
|
|
145
145
|
const baseDir = options.outDir ?? loadContext().output_dir ?? process.cwd();
|
|
146
146
|
const dir = defaultOutputDir(baseDir, name, taskId);
|
|
147
|
-
const dlSpinner = createSpinner(
|
|
147
|
+
const dlSpinner = createSpinner('downloading artifacts…', isQuiet());
|
|
148
148
|
try {
|
|
149
149
|
const artifacts = await downloadArtifacts(task, dir, entry, {
|
|
150
|
-
onFile: (f) => dlSpinner.update(
|
|
150
|
+
onFile: (f) => dlSpinner.update(`downloading ${f}`),
|
|
151
151
|
});
|
|
152
|
-
dlSpinner.succeed(
|
|
152
|
+
dlSpinner.succeed(`artifacts saved to ${artifacts.outputDir}`);
|
|
153
153
|
result.output_dir = artifacts.outputDir;
|
|
154
154
|
result.files = artifacts.files.map((f) => basename(f));
|
|
155
155
|
result.model_file = artifacts.modelFile;
|
|
@@ -157,13 +157,12 @@ export async function runTask(options) {
|
|
|
157
157
|
updateHistoryStatus(taskId, 'success', { output_dir: artifacts.outputDir });
|
|
158
158
|
}
|
|
159
159
|
catch (err) {
|
|
160
|
-
dlSpinner.fail(
|
|
161
|
-
|
|
162
|
-
warn(t({ zh: `可重试:tripo task get ${taskId} --download`, en: `retry with: tripo task get ${taskId} --download` }));
|
|
160
|
+
dlSpinner.fail('artifact download failed (the task itself succeeded)');
|
|
161
|
+
throw new ArtifactDownloadError(taskId, result, err instanceof Error ? err.message : String(err));
|
|
163
162
|
}
|
|
164
163
|
}
|
|
165
164
|
if (options.notify) {
|
|
166
|
-
notifyDone('Tripo',
|
|
165
|
+
notifyDone('Tripo', `${taskType} finished`);
|
|
167
166
|
}
|
|
168
167
|
return result;
|
|
169
168
|
}
|
package/dist/knowledge/chains.js
CHANGED
|
@@ -22,22 +22,22 @@ export const MODEL_PRODUCING_TYPES = new Set([
|
|
|
22
22
|
'animate_retarget',
|
|
23
23
|
]);
|
|
24
24
|
export const STEPS = [
|
|
25
|
-
{ name: 'texture', endpoint: '/v3/models/texture', produces: 'texture_model', accepts: 'any-model', acceptsFile: true, describe:
|
|
26
|
-
{ name: 'convert', endpoint: '/v3/models/convert', produces: 'convert_model', accepts: 'any-model', acceptsFile: true, describe:
|
|
27
|
-
{ name: 'import', endpoint: '/v3/models/import', produces: 'import_model', accepts: [], acceptsFile: true, describe:
|
|
28
|
-
{ name: 'rig-check', endpoint: '/v3/animations/rig-check', produces: 'animate_prerigcheck', accepts: 'any-model', acceptsFile: true, passthrough: true, aliases: ['check', 'rigcheck'], describe:
|
|
29
|
-
{ name: 'rig', endpoint: '/v3/animations/rig', produces: 'animate_rig', accepts: 'any-model', acceptsFile: true, describe:
|
|
30
|
-
{ name: 'retarget', endpoint: '/v3/animations/retarget', produces: 'animate_retarget', accepts: ['animate_rig'], acceptsFile: false, aliases: ['animate'], describe:
|
|
31
|
-
{ name: 'segment', endpoint: '/v3/mesh/segment', produces: 'mesh_segmentation', accepts: 'any-model', acceptsFile: true, describe:
|
|
32
|
-
{ name: 'complete', endpoint: '/v3/mesh/complete', produces: 'mesh_completion', accepts: ['mesh_segmentation'], acceptsFile: false, describe:
|
|
33
|
-
{ name: 'decimate', endpoint: '/v3/mesh/decimate', produces: 'highpoly_to_lowpoly', accepts: 'any-model', acceptsFile: true, aliases: ['lowpoly'], describe:
|
|
34
|
-
{ name: 'uv', endpoint: '/v3/mesh/uv', produces: 'mesh_uv', accepts: 'any-model', acceptsFile: true, describe:
|
|
25
|
+
{ name: 'texture', endpoint: '/v3/models/texture', produces: 'texture_model', accepts: 'any-model', acceptsFile: true, describe: 'regenerate textures / PBR materials' },
|
|
26
|
+
{ name: 'convert', endpoint: '/v3/models/convert', produces: 'convert_model', accepts: 'any-model', acceptsFile: true, describe: 'convert format / texture size / orientation' },
|
|
27
|
+
{ name: 'import', endpoint: '/v3/models/import', produces: 'import_model', accepts: [], acceptsFile: true, describe: 'import a local model file as the chain source' },
|
|
28
|
+
{ name: 'rig-check', endpoint: '/v3/animations/rig-check', produces: 'animate_prerigcheck', accepts: 'any-model', acceptsFile: true, passthrough: true, aliases: ['check', 'rigcheck'], describe: 'check riggability (no model output; stops the chain if not riggable)' },
|
|
29
|
+
{ name: 'rig', endpoint: '/v3/animations/rig', produces: 'animate_rig', accepts: 'any-model', acceptsFile: true, describe: 'auto-rig a skeleton' },
|
|
30
|
+
{ name: 'retarget', endpoint: '/v3/animations/retarget', produces: 'animate_retarget', accepts: ['animate_rig'], acceptsFile: false, aliases: ['animate'], describe: 'retarget preset animations onto the rigged model' },
|
|
31
|
+
{ name: 'segment', endpoint: '/v3/mesh/segment', produces: 'mesh_segmentation', accepts: 'any-model', acceptsFile: true, describe: 'segment the mesh into parts' },
|
|
32
|
+
{ name: 'complete', endpoint: '/v3/mesh/complete', produces: 'mesh_completion', accepts: ['mesh_segmentation'], acceptsFile: false, describe: 'complete the segmented parts' },
|
|
33
|
+
{ name: 'decimate', endpoint: '/v3/mesh/decimate', produces: 'highpoly_to_lowpoly', accepts: 'any-model', acceptsFile: true, aliases: ['lowpoly'], describe: 'decimate to a target face count' },
|
|
34
|
+
{ name: 'uv', endpoint: '/v3/mesh/uv', produces: 'mesh_uv', accepts: 'any-model', acceptsFile: true, describe: 'smart UV unwrap; remaps textures/rig/animation onto the new layout' },
|
|
35
35
|
// mesh/edit: local retry/refine inside a bbox, P2 pipeline (model fixed to P2-20260801).
|
|
36
|
-
{ name: 'edit', endpoint: '/v3/mesh/edit', produces: 'mesh_edit', accepts: 'any-model', acceptsFile: true, describe:
|
|
36
|
+
{ name: 'edit', endpoint: '/v3/mesh/edit', produces: 'mesh_edit', accepts: 'any-model', acceptsFile: true, describe: 'redo one bbox region locally (P2 pipeline)' },
|
|
37
37
|
// smartsegment's `input` is file_token/URL only (the server does not resolve
|
|
38
38
|
// task ids here), so it cannot chain after a task. Type is refined to
|
|
39
39
|
// smartsegment_image|smartsegment_model at request-build time per seg_type.
|
|
40
|
-
{ name: 'smartsegment', endpoint: '/v3/mesh/smartsegment', produces: 'smartsegment_model', accepts: [], acceptsFile: true, describe:
|
|
40
|
+
{ name: 'smartsegment', endpoint: '/v3/mesh/smartsegment', produces: 'smartsegment_model', accepts: [], acceptsFile: true, describe: 'smart semantic segmentation' },
|
|
41
41
|
];
|
|
42
42
|
const stepIndex = new Map();
|
|
43
43
|
for (const s of STEPS) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* V3 error-code catalog: human
|
|
2
|
+
* V3 error-code catalog: human-readable messages, retryability, and the
|
|
3
3
|
* CLI exit code each error maps to.
|
|
4
4
|
*
|
|
5
5
|
* Source of truth: backend ErrorCode enum (platform-common .../error/ErrorCode.java,
|
|
@@ -20,37 +20,37 @@ export const EXIT = {
|
|
|
20
20
|
RATE_LIMIT: 9,
|
|
21
21
|
};
|
|
22
22
|
export const ERROR_CATALOG = [
|
|
23
|
-
{ code: 1000,
|
|
24
|
-
{ code: 1001,
|
|
25
|
-
{ code: 1002,
|
|
26
|
-
{ code: 1003,
|
|
27
|
-
{ code: 1004,
|
|
28
|
-
{ code: 1005,
|
|
29
|
-
{ code: 1007,
|
|
30
|
-
{ code: 2000,
|
|
31
|
-
{ code: 2001,
|
|
32
|
-
{ code: 2002,
|
|
33
|
-
{ code: 2003,
|
|
34
|
-
{ code: 2004,
|
|
35
|
-
{ code: 2005,
|
|
36
|
-
{ code: 2006,
|
|
37
|
-
{ code: 2007,
|
|
38
|
-
{ code: 2008,
|
|
39
|
-
{ code: 2009,
|
|
40
|
-
{ code: 2010,
|
|
41
|
-
{ code: 2011,
|
|
42
|
-
{ code: 2012,
|
|
43
|
-
{ code: 2013,
|
|
44
|
-
{ code: 2014,
|
|
45
|
-
{ code: 2015,
|
|
46
|
-
{ code: 2016,
|
|
47
|
-
{ code: 2017,
|
|
48
|
-
{ code: 2018,
|
|
49
|
-
{ code: 2019,
|
|
50
|
-
{ code: 2020,
|
|
51
|
-
{ code: 2021,
|
|
52
|
-
{ code: 2022,
|
|
53
|
-
{ code: 4001,
|
|
23
|
+
{ code: 1000, message: 'Unknown server-side error; contact support with the request id', retryable: true, exitCode: EXIT.NETWORK },
|
|
24
|
+
{ code: 1001, message: 'Fatal server-side error; contact support with the request id', retryable: false, exitCode: EXIT.NETWORK },
|
|
25
|
+
{ code: 1002, message: 'Authentication failed: invalid key or wrong region (cn key against the ov API?) — run "tripo doctor" to auto-diagnose', retryable: false, exitCode: EXIT.AUTH },
|
|
26
|
+
{ code: 1003, message: 'The request body is malformed', retryable: false, exitCode: EXIT.USAGE },
|
|
27
|
+
{ code: 1004, message: 'One or more parameters are invalid (check the docs)', retryable: false, exitCode: EXIT.USAGE },
|
|
28
|
+
{ code: 1005, message: 'Not allowed to access this resource (check permissions)', retryable: false, exitCode: EXIT.AUTH },
|
|
29
|
+
{ code: 1007, message: 'Rate limit exceeded — too many requests in a short time', retryable: true, exitCode: EXIT.RATE_LIMIT },
|
|
30
|
+
{ code: 2000, message: 'Generation concurrency limit hit (task families share a pool)', retryable: true, exitCode: EXIT.RATE_LIMIT },
|
|
31
|
+
{ code: 2001, message: 'Task not found (same key that created it? right region?)', retryable: false, exitCode: EXIT.NOT_FOUND },
|
|
32
|
+
{ code: 2002, message: 'Unsupported request parameter (check field names and values)', retryable: false, exitCode: EXIT.USAGE },
|
|
33
|
+
{ code: 2003, message: 'The input file is empty (corrupted upload?)', retryable: false, exitCode: EXIT.USAGE },
|
|
34
|
+
{ code: 2004, message: 'Unsupported file type', retryable: false, exitCode: EXIT.USAGE },
|
|
35
|
+
{ code: 2005, message: 'The draft task is not a success; retry with a successful one', retryable: false, exitCode: EXIT.USAGE },
|
|
36
|
+
{ code: 2006, message: 'The original task type is not supported for this operation', retryable: false, exitCode: EXIT.USAGE },
|
|
37
|
+
{ code: 2007, message: 'The original task has not succeeded', retryable: false, exitCode: EXIT.USAGE },
|
|
38
|
+
{ code: 2008, message: 'Input violates the content policy; change the input', retryable: false, exitCode: EXIT.CONTENT_POLICY },
|
|
39
|
+
{ code: 2009, message: 'The prompt contains invalid characters', retryable: false, exitCode: EXIT.USAGE },
|
|
40
|
+
{ code: 2010, message: 'Insufficient credits', retryable: false, exitCode: EXIT.BALANCE },
|
|
41
|
+
{ code: 2011, message: 'The rig-check input task has no model output', retryable: false, exitCode: EXIT.USAGE },
|
|
42
|
+
{ code: 2012, message: 'retarget only accepts a rig task as input', retryable: false, exitCode: EXIT.USAGE },
|
|
43
|
+
{ code: 2013, message: 'Invalid priority (contact support for higher priority)', retryable: false, exitCode: EXIT.USAGE },
|
|
44
|
+
{ code: 2014, message: 'Error occurred during content auditing; contact support', retryable: false, exitCode: EXIT.FATAL },
|
|
45
|
+
{ code: 2015, message: 'Model version deprecated; upgrade the model parameter', retryable: false, exitCode: EXIT.USAGE },
|
|
46
|
+
{ code: 2016, message: 'This request type is deprecated; use an alternative', retryable: false, exitCode: EXIT.USAGE },
|
|
47
|
+
{ code: 2017, message: 'The model version value is invalid', retryable: false, exitCode: EXIT.USAGE },
|
|
48
|
+
{ code: 2018, message: 'Model too complex to remesh; lower face_limit or simplify input', retryable: false, exitCode: EXIT.USAGE },
|
|
49
|
+
{ code: 2019, message: 'File not found (upload succeeded? token expired?)', retryable: false, exitCode: EXIT.NOT_FOUND },
|
|
50
|
+
{ code: 2020, message: 'The image URL is invalid (must be publicly reachable)', retryable: false, exitCode: EXIT.USAGE },
|
|
51
|
+
{ code: 2021, message: 'File size exceeds the limit; reduce and retry', retryable: false, exitCode: EXIT.USAGE },
|
|
52
|
+
{ code: 2022, message: 'Image size exceeds the limit; reduce and retry', retryable: false, exitCode: EXIT.USAGE },
|
|
53
|
+
{ code: 4001, message: 'The requested endpoint does not exist (check the API path)', retryable: false, exitCode: EXIT.NOT_FOUND },
|
|
54
54
|
];
|
|
55
55
|
const byCode = new Map(ERROR_CATALOG.map((e) => [e.code, e]));
|
|
56
56
|
export function lookupError(code) {
|