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/pipeline/make.js
CHANGED
|
@@ -1,22 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The `make` orchestrator — one entry point that turns any input (text /
|
|
3
3
|
* image / multiview / model file / task ref) into finished artifacts,
|
|
4
|
-
* applying
|
|
4
|
+
* applying model routing, scenario presets, and the processing chain.
|
|
5
5
|
* Shared by `tripo make`, `tripo ai`, `tripo redo`, batch, and the MCP server.
|
|
6
6
|
*/
|
|
7
7
|
import { basename } from 'node:path';
|
|
8
8
|
import { UsageError } from '../core/errors.js';
|
|
9
9
|
import { log, warn } from '../core/output.js';
|
|
10
|
-
import { buildImageToModel, buildMultiviewToModel, buildStepRequest, buildTextToModel, } from '../core/requests.js';
|
|
10
|
+
import { buildImageToModel, buildMultiviewToModel, buildStepRequest, buildTextToModel, validateChainRequests, } from '../core/requests.js';
|
|
11
11
|
import { precheckBalance, resolveInputValue, runTask } from '../core/task-service.js';
|
|
12
|
-
import { t } from '../i18n.js';
|
|
13
12
|
import { validateChain, ChainError } from '../knowledge/chains.js';
|
|
14
|
-
import { chooseModel, detectLowPolyIntent } from '../knowledge/models.js';
|
|
13
|
+
import { chooseModel, detectDenseGeometryIntent, detectLowPolyIntent, detectRealtimeIntent } from '../knowledge/models.js';
|
|
15
14
|
import { getScenario } from '../knowledge/scenarios.js';
|
|
16
15
|
import { classifyInputs } from '../util/input-detect.js';
|
|
17
16
|
import { runChain, assertSourceReady } from './runner.js';
|
|
18
|
-
|
|
17
|
+
function chooseGenerationModel(options, scenario, genParams, prompt) {
|
|
18
|
+
return chooseModel({
|
|
19
|
+
explicit: options.model,
|
|
20
|
+
preferred: scenario?.model,
|
|
21
|
+
faceLimit: typeof genParams.face_limit === 'number' ? genParams.face_limit : undefined,
|
|
22
|
+
quad: genParams.quad === true,
|
|
23
|
+
lowPoly: prompt ? detectLowPolyIntent(prompt) : false,
|
|
24
|
+
realtime: prompt ? detectRealtimeIntent(prompt) : false,
|
|
25
|
+
denseGeometry: prompt ? detectDenseGeometryIntent(prompt) : false,
|
|
26
|
+
params: genParams,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/** Validate the entire plan without side effects before resolving uploads. */
|
|
19
30
|
export async function planMake(client, options) {
|
|
31
|
+
const preview = await prepareMake(client, { ...options, dryRun: true });
|
|
32
|
+
checkPlanChain(preview);
|
|
33
|
+
return options.dryRun ? preview : prepareMake(client, options);
|
|
34
|
+
}
|
|
35
|
+
async function prepareMake(client, options) {
|
|
20
36
|
const classified = classifyInputs(options.inputs);
|
|
21
37
|
const scenario = options.scenario ? getScenario(options.scenario) : undefined;
|
|
22
38
|
if (options.scenario && !scenario) {
|
|
@@ -25,25 +41,21 @@ export async function planMake(client, options) {
|
|
|
25
41
|
const userParams = options.params ?? {};
|
|
26
42
|
const genParams = { ...(scenario?.genParams ?? {}), ...userParams };
|
|
27
43
|
const chain = options.chain && options.chain.length > 0 ? options.chain : (scenario?.chain ?? []);
|
|
44
|
+
// --then replaces the scenario chain, so its dual-delivery promise no longer holds.
|
|
45
|
+
const downloadGeneration = scenario?.downloadGeneration === true && !(options.chain && options.chain.length > 0);
|
|
28
46
|
const warnings = [];
|
|
29
47
|
if (options.chain && options.chain.length > 0 && scenario && scenario.chain.length > 0) {
|
|
30
|
-
warnings.push(
|
|
31
|
-
zh: `--then 覆盖了 ${scenario.id} 场景默认加工链`,
|
|
32
|
-
en: `--then overrides the default ${scenario.id} processing chain`,
|
|
33
|
-
}));
|
|
48
|
+
warnings.push(`--then overrides the default ${scenario.id} processing chain`);
|
|
34
49
|
}
|
|
35
50
|
switch (classified.kind) {
|
|
36
51
|
case 'text': {
|
|
37
52
|
const prompt = classified.values[0].value;
|
|
38
|
-
const choice =
|
|
39
|
-
explicit: options.model ?? scenario?.model,
|
|
40
|
-
faceLimit: typeof genParams.face_limit === 'number' ? genParams.face_limit : undefined,
|
|
41
|
-
lowPoly: detectLowPolyIntent(prompt),
|
|
42
|
-
});
|
|
53
|
+
const choice = chooseGenerationModel(options, scenario, genParams, prompt);
|
|
43
54
|
const generation = buildTextToModel(prompt, choice.model, genParams);
|
|
44
55
|
return {
|
|
45
56
|
generation,
|
|
46
57
|
chain,
|
|
58
|
+
downloadGeneration,
|
|
47
59
|
model: choice.model,
|
|
48
60
|
modelReason: choice.reason,
|
|
49
61
|
name: options.name ?? prompt,
|
|
@@ -54,14 +66,12 @@ export async function planMake(client, options) {
|
|
|
54
66
|
case 'url-image': {
|
|
55
67
|
const raw = classified.values[0].value;
|
|
56
68
|
const { value } = await resolveInputValue(client, raw, { dryRun: options.dryRun });
|
|
57
|
-
const choice =
|
|
58
|
-
explicit: options.model ?? scenario?.model,
|
|
59
|
-
faceLimit: typeof genParams.face_limit === 'number' ? genParams.face_limit : undefined,
|
|
60
|
-
});
|
|
69
|
+
const choice = chooseGenerationModel(options, scenario, genParams);
|
|
61
70
|
const generation = buildImageToModel(value, choice.model, genParams);
|
|
62
71
|
return {
|
|
63
72
|
generation,
|
|
64
73
|
chain,
|
|
74
|
+
downloadGeneration,
|
|
65
75
|
model: choice.model,
|
|
66
76
|
modelReason: choice.reason,
|
|
67
77
|
name: options.name ?? basename(raw),
|
|
@@ -70,14 +80,12 @@ export async function planMake(client, options) {
|
|
|
70
80
|
}
|
|
71
81
|
case 'multiview': {
|
|
72
82
|
const views = await assignViews(client, classified.values.map((v) => v.value), { dryRun: options.dryRun });
|
|
73
|
-
const choice =
|
|
74
|
-
explicit: options.model ?? scenario?.model,
|
|
75
|
-
faceLimit: typeof genParams.face_limit === 'number' ? genParams.face_limit : undefined,
|
|
76
|
-
});
|
|
83
|
+
const choice = chooseGenerationModel(options, scenario, genParams);
|
|
77
84
|
const generation = buildMultiviewToModel(views, choice.model, genParams);
|
|
78
85
|
return {
|
|
79
86
|
generation,
|
|
80
87
|
chain,
|
|
88
|
+
downloadGeneration,
|
|
81
89
|
model: choice.model,
|
|
82
90
|
modelReason: choice.reason,
|
|
83
91
|
name: options.name ?? basename(classified.values[0].value),
|
|
@@ -89,10 +97,7 @@ export async function planMake(client, options) {
|
|
|
89
97
|
const { value } = await resolveInputValue(client, raw, { dryRun: options.dryRun });
|
|
90
98
|
const generation = buildStepRequest('import', value, {});
|
|
91
99
|
if (chain.length === 0) {
|
|
92
|
-
warnings.push(
|
|
93
|
-
zh: '导入模型后没有加工步骤;用 --then 指定(如 --then texture,rig)',
|
|
94
|
-
en: 'importing a model with no processing steps; add --then (e.g. --then texture,rig)',
|
|
95
|
-
}));
|
|
100
|
+
warnings.push('importing a model with no processing steps; add --then (e.g. --then texture,rig)');
|
|
96
101
|
}
|
|
97
102
|
return {
|
|
98
103
|
generation,
|
|
@@ -121,6 +126,7 @@ export async function planMake(client, options) {
|
|
|
121
126
|
* Skipped when the upstream type is unknown (raw task id without local history).
|
|
122
127
|
*/
|
|
123
128
|
export function checkPlanChain(plan) {
|
|
129
|
+
validateChainRequests(plan.chain);
|
|
124
130
|
if (plan.chain.length === 0)
|
|
125
131
|
return;
|
|
126
132
|
const upstream = plan.generation?.taskType ?? plan.sourceType;
|
|
@@ -147,7 +153,7 @@ export async function executeMake(client, plan, options) {
|
|
|
147
153
|
let primary;
|
|
148
154
|
if (plan.generation) {
|
|
149
155
|
if (plan.model && plan.modelReason) {
|
|
150
|
-
log(
|
|
156
|
+
log(`model: ${plan.model} (${plan.modelReason})`);
|
|
151
157
|
}
|
|
152
158
|
primary = await runTask({
|
|
153
159
|
client,
|
|
@@ -156,10 +162,11 @@ export async function executeMake(client, plan, options) {
|
|
|
156
162
|
name: plan.name,
|
|
157
163
|
outDir: options.outDir,
|
|
158
164
|
noWait: options.noWait,
|
|
159
|
-
noDownload: options.noDownload || plan.chain.length > 0,
|
|
165
|
+
noDownload: options.noDownload || (plan.chain.length > 0 && !plan.downloadGeneration),
|
|
160
166
|
timeoutMs: options.timeoutMs,
|
|
161
167
|
notify: options.notify && plan.chain.length === 0,
|
|
162
168
|
precheckBalance: false,
|
|
169
|
+
onCreated: options.onTaskCreated,
|
|
163
170
|
});
|
|
164
171
|
if (options.noWait)
|
|
165
172
|
return { primary, chainResults: [] };
|
|
@@ -183,6 +190,7 @@ export async function executeMake(client, plan, options) {
|
|
|
183
190
|
outDir: options.outDir,
|
|
184
191
|
notify: false,
|
|
185
192
|
timeoutMs: options.timeoutMs,
|
|
193
|
+
onTaskCreated: options.onTaskCreated,
|
|
186
194
|
});
|
|
187
195
|
// If the chain stopped early (not riggable) and no step downloaded a model,
|
|
188
196
|
// fetch the source artifacts so the user still gets their model.
|
package/dist/pipeline/runner.js
CHANGED
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { UsageError } from '../core/errors.js';
|
|
7
7
|
import { log, warn } from '../core/output.js';
|
|
8
|
-
import { buildStepRequest } from '../core/requests.js';
|
|
8
|
+
import { buildStepRequest, validateChainRequests } from '../core/requests.js';
|
|
9
9
|
import { runTask } from '../core/task-service.js';
|
|
10
|
-
import { t } from '../i18n.js';
|
|
11
10
|
import { getStep, validateChain } from '../knowledge/chains.js';
|
|
12
11
|
import { NON_BIPED_PRESETS } from '../knowledge/models.js';
|
|
13
12
|
export async function runChain(options) {
|
|
14
13
|
const { client, chain } = options;
|
|
15
14
|
validateChain(chain, options.sourceType);
|
|
15
|
+
validateChainRequests(chain);
|
|
16
16
|
const results = [];
|
|
17
17
|
let currentTaskId = options.sourceTaskId;
|
|
18
18
|
let rigTypeRecommendation;
|
|
@@ -22,7 +22,7 @@ export async function runChain(options) {
|
|
|
22
22
|
const args = { ...spec.args };
|
|
23
23
|
if (spec.step === 'rig' && rigTypeRecommendation && args.rig_type === undefined) {
|
|
24
24
|
args.rig_type = rigTypeRecommendation;
|
|
25
|
-
log(
|
|
25
|
+
log(`using rig-check recommendation: ${rigTypeRecommendation}`);
|
|
26
26
|
}
|
|
27
27
|
if (spec.step === 'rig')
|
|
28
28
|
rigType = String(args.rig_type ?? 'biped');
|
|
@@ -33,7 +33,7 @@ export async function runChain(options) {
|
|
|
33
33
|
if (requested.length > 0 && requested.every((a) => /^preset:[^:]+$/.test(a))) {
|
|
34
34
|
delete args.animation;
|
|
35
35
|
args.animations = bodyPresets;
|
|
36
|
-
log(
|
|
36
|
+
log(`rig type is ${rigType}: biped presets swapped for ${bodyPresets.join(', ')}`);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
// avian/others have no preset animations: the rigged model is the final output.
|
|
@@ -52,13 +52,11 @@ export async function runChain(options) {
|
|
|
52
52
|
// Intermediate steps skip download; final step downloads.
|
|
53
53
|
noDownload: i < chain.length - 1 && spec.step !== 'rig-check' && !noPresets,
|
|
54
54
|
precheckBalance: false, // checked once by the caller
|
|
55
|
+
onCreated: options.onTaskCreated,
|
|
55
56
|
});
|
|
56
57
|
results.push(result);
|
|
57
58
|
if (noPresets) {
|
|
58
|
-
const message =
|
|
59
|
-
zh: `体型 ${rigType} 没有预设动画,已跳过 retarget,产物为绑骨模型`,
|
|
60
|
-
en: `rig type ${rigType} has no preset animations; skipped retarget and kept the rigged model`,
|
|
61
|
-
});
|
|
59
|
+
const message = `rig type ${rigType} has no preset animations; skipped retarget and kept the rigged model`;
|
|
62
60
|
warn(message);
|
|
63
61
|
return { results, stoppedEarly: message };
|
|
64
62
|
}
|
|
@@ -68,10 +66,7 @@ export async function runChain(options) {
|
|
|
68
66
|
const riggable = output.riggable;
|
|
69
67
|
rigTypeRecommendation = typeof output.rig_type === 'string' ? output.rig_type : undefined;
|
|
70
68
|
if (riggable === false) {
|
|
71
|
-
const message =
|
|
72
|
-
zh: 'rig-check 判定该模型不可绑骨,动画链止损停止(后续步骤未执行,未扣积分)',
|
|
73
|
-
en: 'rig-check says this model is not riggable; stopping the chain early (no further credits spent)',
|
|
74
|
-
});
|
|
69
|
+
const message = 'rig-check says this model is not riggable; stopping the chain early (no further credits spent)';
|
|
75
70
|
warn(message);
|
|
76
71
|
return { results, stoppedEarly: message };
|
|
77
72
|
}
|
package/dist/pipeline/stdin.js
CHANGED
|
@@ -2,12 +2,48 @@
|
|
|
2
2
|
* NDJSON pipe support: downstream commands read the upstream task result from
|
|
3
3
|
* stdin, enabling `tripo make cat.png | tripo model texture | tripo anim rig`.
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
import { CliError, UsageError } from '../core/errors.js';
|
|
6
|
+
import { EXIT } from '../knowledge/error-catalog.js';
|
|
7
|
+
/**
|
|
8
|
+
* Read piped NDJSON/JSON from stdin; returns undefined only on a TTY.
|
|
9
|
+
* Piped input that carries an upstream error or no task throws, so a broken
|
|
10
|
+
* pipeline never falls back to some other task and spends credits on it.
|
|
11
|
+
*/
|
|
6
12
|
export async function readPipedTask() {
|
|
7
13
|
if (process.stdin.isTTY)
|
|
8
14
|
return undefined;
|
|
9
15
|
const raw = await readAll(process.stdin);
|
|
10
|
-
|
|
16
|
+
const upstream = parsePipedError(raw);
|
|
17
|
+
if (upstream) {
|
|
18
|
+
const code = upstream.exit_code;
|
|
19
|
+
const exitCode = code !== undefined && Number.isInteger(code) && code >= 1 && code <= 9 ? code : EXIT.USAGE;
|
|
20
|
+
throw new CliError(`upstream command failed${code !== undefined ? ` (exit ${code})` : ''}: ${upstream.error}; nothing was submitted`, exitCode);
|
|
21
|
+
}
|
|
22
|
+
const task = parsePipedText(raw);
|
|
23
|
+
if (!task) {
|
|
24
|
+
throw new UsageError('no task on stdin (piped input was empty or carried no task_id); nothing was submitted', 'pass the input explicitly, e.g. "tripo model texture @last" or a task id');
|
|
25
|
+
}
|
|
26
|
+
return task;
|
|
27
|
+
}
|
|
28
|
+
/** The upstream error when the last JSON line is an error object (`{"error","exit_code"}`). */
|
|
29
|
+
export function parsePipedError(raw) {
|
|
30
|
+
const lines = raw.trim().split('\n').map((l) => l.trim()).filter(Boolean);
|
|
31
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
32
|
+
let obj;
|
|
33
|
+
try {
|
|
34
|
+
obj = JSON.parse(lines[i]);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (typeof obj !== 'object' || obj === null)
|
|
40
|
+
continue;
|
|
41
|
+
const { error, exit_code: exitCode } = obj;
|
|
42
|
+
if (typeof error !== 'string')
|
|
43
|
+
return undefined;
|
|
44
|
+
return { error, exit_code: typeof exitCode === 'number' ? exitCode : undefined };
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
11
47
|
}
|
|
12
48
|
/** Parse piped text: JSON object, NDJSON (last task line wins), or a bare task id. */
|
|
13
49
|
export function parsePipedText(raw) {
|
|
@@ -18,7 +54,8 @@ export function parsePipedText(raw) {
|
|
|
18
54
|
for (let i = lines.length - 1; i >= 0; i--) {
|
|
19
55
|
try {
|
|
20
56
|
const obj = JSON.parse(lines[i]);
|
|
21
|
-
|
|
57
|
+
// Error JSON may name the failed task; it is never an input.
|
|
58
|
+
if (typeof obj.task_id === 'string' && obj.error === undefined) {
|
|
22
59
|
return { task_id: obj.task_id, type: typeof obj.type === 'string' ? obj.type : undefined };
|
|
23
60
|
}
|
|
24
61
|
}
|
package/dist/program.js
CHANGED
|
@@ -13,16 +13,15 @@ import { registerGenerateCommands } from './commands/generate.js';
|
|
|
13
13
|
import { registerHomeAction } from './commands/home.js';
|
|
14
14
|
import { registerMakeCommand } from './commands/make.js';
|
|
15
15
|
import { registerMcpCommand } from './commands/mcp.js';
|
|
16
|
+
import { registerModelsCommand } from './commands/models.js';
|
|
16
17
|
import { registerProcessCommands } from './commands/process-groups.js';
|
|
17
18
|
import { registerTaskCommands } from './commands/task.js';
|
|
18
19
|
import { registerTopupCommand } from './commands/topup.js';
|
|
19
20
|
import { notifyIfOutdated, registerUpdateCommand } from './commands/update.js';
|
|
20
21
|
import { registerViewCommands } from './commands/view.js';
|
|
21
|
-
import { loadConfig } from './config/config.js';
|
|
22
22
|
import { RefError } from './config/history.js';
|
|
23
|
-
import { ApiError, CliError, UsageError } from './core/errors.js';
|
|
23
|
+
import { ApiError, ArtifactDownloadError, CliError, TaskFailedError, UsageError } from './core/errors.js';
|
|
24
24
|
import { configureOutput, errorLine, isJsonMode } from './core/output.js';
|
|
25
|
-
import { setLocale, t } from './i18n.js';
|
|
26
25
|
import { EXIT } from './knowledge/error-catalog.js';
|
|
27
26
|
import { cliVersion } from './version.js';
|
|
28
27
|
import { beginOperation, finishOperation } from './core/analytics.js';
|
|
@@ -30,10 +29,7 @@ export function buildProgram() {
|
|
|
30
29
|
const program = new Command();
|
|
31
30
|
program
|
|
32
31
|
.name('tripo')
|
|
33
|
-
.description(
|
|
34
|
-
zh: 'Tripo 3D 智能 CLI — 一句话/一张图,直出可进引擎的 3D 资产\n高频: make(生成) ai(专家规划) view(预览) topup(充值)',
|
|
35
|
-
en: 'Tripo 3D intelligent CLI — turn a sentence or an image into engine-ready 3D assets\ntop commands: make · ai · view · topup',
|
|
36
|
-
}))
|
|
32
|
+
.description('Tripo 3D intelligent CLI — turn a sentence or an image into engine-ready 3D assets\ntop commands: make · ai · view · topup')
|
|
37
33
|
.version(cliVersion(), '-v, --version')
|
|
38
34
|
.option('--json', 'machine-readable output on stdout (auto-enabled when piped)')
|
|
39
35
|
.option('--yes', 'skip confirmations (auto-enabled when headless)')
|
|
@@ -54,13 +50,10 @@ export function buildProgram() {
|
|
|
54
50
|
const profile = resolveGlobalString(actionCommand, 'profile');
|
|
55
51
|
if (profile)
|
|
56
52
|
process.env.TRIPO_PROFILE = profile;
|
|
57
|
-
const lang = loadConfig().language;
|
|
58
|
-
if (lang)
|
|
59
|
-
setLocale(lang);
|
|
60
53
|
const path = [];
|
|
61
54
|
for (let command = actionCommand; command && command !== program; command = command.parent)
|
|
62
55
|
path.unshift(command.name());
|
|
63
|
-
const excluded = ['mcp', 'docs', 'completion', 'config', 'update', 'use', 'logout', 'home'];
|
|
56
|
+
const excluded = ['mcp', 'docs', 'completion', 'config', 'update', 'use', 'logout', 'home', 'models'];
|
|
64
57
|
if (actionCommand.name() !== 'mcp')
|
|
65
58
|
beginOperation(path.join(':'), path.length === 0 || excluded.includes(path[0]) || actionCommand.opts().dryRun === true, undefined, actionCommand.opts().region === 'cn' || actionCommand.opts().region === 'ov' ? actionCommand.opts().region : undefined);
|
|
66
59
|
// Startup version hint (cached, non-blocking). `update` reports on its
|
|
@@ -75,6 +68,7 @@ export function buildProgram() {
|
|
|
75
68
|
registerAuthCommands(program);
|
|
76
69
|
registerTopupCommand(program);
|
|
77
70
|
registerAccountCommands(program);
|
|
71
|
+
registerModelsCommand(program);
|
|
78
72
|
registerGenerateCommands(program);
|
|
79
73
|
registerProcessCommands(program);
|
|
80
74
|
registerTaskCommands(program);
|
|
@@ -158,6 +152,7 @@ export function handleError(err) {
|
|
|
158
152
|
...(err instanceof ApiError
|
|
159
153
|
? { api_code: err.apiCode, request_id: err.requestId, http_status: err.httpStatus }
|
|
160
154
|
: {}),
|
|
155
|
+
...(err instanceof TaskFailedError || err instanceof ArtifactDownloadError ? { task_id: err.taskId } : {}),
|
|
161
156
|
...(err.suggestion ? { suggestion: err.suggestion } : {}),
|
|
162
157
|
}) + '\n');
|
|
163
158
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tripo-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Tripo 3D intelligent CLI — turn a prompt or an image into engine-ready 3D assets from your terminal (Tripo V3 API)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tripo",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"files": [
|
|
21
21
|
"dist",
|
|
22
22
|
"skill",
|
|
23
|
+
"CHANGELOG.md",
|
|
23
24
|
"README.md"
|
|
24
25
|
],
|
|
25
26
|
"engines": {
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
"@clack/prompts": "^1.7.0",
|
|
49
50
|
"commander": "^15.0.0",
|
|
50
51
|
"picocolors": "^1.1.1",
|
|
51
|
-
"undici": "^6.
|
|
52
|
+
"undici": "^6.29.1",
|
|
52
53
|
"yaml": "^2.9.0"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
package/skill/SKILL.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tripo-cli
|
|
3
|
+
description: Generate and process 3D models with the Tripo API through the tripo CLI - text or images to GLB/FBX/OBJ/STL/USDZ, texturing, rigging, animation, mesh tools and format conversion, with plan cards and credit estimates. Use when the user wants to create, convert, rig, animate or 3D-print a 3D asset, or mentions Tripo.
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# Tripo CLI Skill
|
|
2
7
|
|
|
8
|
+
**Bundled with tripo-cli 0.8.1.**
|
|
9
|
+
|
|
10
|
+
- Display aliases `H3.1`, `H3.0`, `H2.5`, `P1.0`, `P2.0` (case-insensitive) normalize before validation; unknown 3D/image model IDs fail locally.
|
|
11
|
+
- `make` validates deterministic later steps before uploading or generating.
|
|
12
|
+
- Plan cards and `--dry-run` JSON (`generation_credits_estimate`) show the official list-price estimate for the generation step; P1, legacy models and `--then` chain steps are **not estimated**, which never means zero credits.
|
|
13
|
+
- Do not interpret `valid=true` as a quotation or proof that arbitrary passthrough fields are supported. Check warnings and the normalized payload: unsupported P-series fields are removed with warnings, not sent to the API.
|
|
14
|
+
- Image model `chat_image_1` is retired and rejected; `chat_image_1.5` is still valid (announced retirement 2026-12-01).
|
|
15
|
+
- Never automatically swap models and resubmit a paid task.
|
|
16
|
+
|
|
3
17
|
You (an AI coding agent) can generate production-ready 3D assets with the `tripo` CLI.
|
|
4
18
|
One command turns a text prompt or an image into local files: a 3D model (glb/fbx/stl/...), a `preview.png` render, and a `task.json` record.
|
|
5
19
|
|
|
@@ -49,13 +63,23 @@ Regions (ov = international, cn = China mainland) share one CLI: `tripo login --
|
|
|
49
63
|
## Behavior rules (read first)
|
|
50
64
|
|
|
51
65
|
1. **`tripo make` is synchronous and blocking.** It prints a plan card on stderr (one numbered line per API call: endpoint, purpose, args), then submits, polls, downloads artifacts, and exits. In a TTY it asks "Run this plan?" first; `--yes` (auto-enabled when headless) skips the prompt but still prints the card. Wait for the process to finish and read the final JSON from stdout. Do NOT re-implement polling, do NOT add your own timeout shorter than 15 minutes, do NOT stop just because you saw a task_id in the logs.
|
|
52
|
-
2. **stdout is the contract; stderr is commentary.** With `--json` (auto-enabled when piped),
|
|
53
|
-
3. **Artifacts are local files.** The result JSON has `output_dir`, `model_file`, `preview`. Look at `preview.png` to judge quality
|
|
66
|
+
2. **stdout is the contract; stderr is commentary.** With `--json` (auto-enabled when piped), every result command prints exactly one JSON line on stdout (`docs`/`completion` print text, `mcp` speaks JSON-RPC). Progress/logs go to stderr.
|
|
67
|
+
3. **Artifacts are local files.** The result JSON has `output_dir`, `model_file`, `preview`. Look at `preview.png` to judge quality. Ask the human before re-rolling: `tripo redo` submits a new paid task at once, with no plan card and no confirmation.
|
|
54
68
|
4. **Exit codes are stable** — branch on them:
|
|
55
|
-
- 0 success · 2 usage/params · 3 auth · 4 insufficient credits (tell the human to run `tripo topup`) · 5 content policy
|
|
69
|
+
- 0 success · 2 usage/params · 3 auth · 4 insufficient credits (tell the human to run `tripo topup`) · 5 content policy
|
|
70
|
+
- 6 task failed (credits auto-refunded; on `timeout` it is still running — `tripo task watch <id>`, never redo)
|
|
71
|
+
- 7 network: a failed submit is never resent and may already exist — check `tripo balance` before re-running. If the task succeeded but its download failed, the error JSON carries `task_id` — run `tripo task get <task_id> --download`, never re-make.
|
|
72
|
+
- 8 not found · 9 rate limit (retry with backoff)
|
|
56
73
|
5. **Never invent parameters.** Unknown `--param key=value` pairs pass through to the API; stick to documented ones. The full parameter/model/preset reference from the official API docs is bundled: `tripo docs --topic commands/generate` (3D + image generation) and `tripo docs --topic commands/process` (texture/convert/rig/retarget/mesh) — read those instead of browsing the website.
|
|
57
74
|
6. **Validate before spending: `--dry-run --json`.** Same command plus `--dry-run` prints the plan as JSON with zero network calls and no credits: the chosen `model`, the completed `steps[].payload` for every API call, `warnings` (auto-adjustments) and `errors` (blocking; exit 2). When `valid` is true, re-run without `--dry-run`. Details: `tripo docs --topic commands/make` § "Dry run".
|
|
58
|
-
7. **
|
|
75
|
+
7. **Route models by use, topology, and geometry.**
|
|
76
|
+
- Explicit `--model` always wins.
|
|
77
|
+
- `tripo-v3.1` (H3.1) is the official default flagship model; the CLI also requires it for dense/high-poly geometry, `smart_low_poly=true`, `generate_parts=true`, any explicit `geometry_quality`, or a face budget outside P2's range (below 48, above 50000, or above 25000 with quad).
|
|
78
|
+
- Next, a `--for` preset outranks prompt hints: `film` and `print` use H3.1; `game-mobile`, `game-pc`, `ar-web`, `anim` and `toy` use P2.
|
|
79
|
+
- Without a preset, the CLI selects `tripo-p2` for real-time/game/editable assets, low-poly or voxel requests, quad topology, and a face budget within P2's range; anything else stays on H3.1.
|
|
80
|
+
- P2 costs 100–130 credits per generation versus 10–50 for H3.1 before add-ons, so before running P2, relay the plan card's estimate to the human and get confirmation.
|
|
81
|
+
- `tripo-p1` is an explicit lower-cost option. Only use legacy `tripo-v3.0` / `tripo-v2.5` to reproduce old projects.
|
|
82
|
+
- `tripo-*` names are CLI aliases — the CLI sends the dated wire value (`tripo-p2` → `P2-20260801`); the API rejects the alias itself with 1004. Alias ↔ wire ↔ status table: `tripo docs --topic commands/generate` ("Models & Versions").
|
|
59
83
|
|
|
60
84
|
## The one command you usually need
|
|
61
85
|
|
|
@@ -67,10 +91,10 @@ tripo make hero.glb --then texture,rig --json --yes # import + process
|
|
|
67
91
|
tripo make @last --then convert:fbx --json --yes # continue from last task
|
|
68
92
|
```
|
|
69
93
|
|
|
70
|
-
- `--for` scenario presets: `game-mobile` `game-pc` `
|
|
94
|
+
- `--for` scenario presets: `film` `print` → H3.1; `game-mobile` `game-pc` `ar-web` `anim` `toy` → P2 (the preset outranks prompt hints; `--model` and H-only requirements still win)
|
|
71
95
|
- `--then` chain steps: `texture convert import rig-check rig retarget segment complete decimate uv smartsegment`
|
|
72
96
|
- step args: `convert:format=FBX,texture_size=2048` (bare value = primary arg: `convert:fbx`, `decimate:5000`)
|
|
73
|
-
- Output JSON: `{"task_id","type","status","credits_consumed","output_dir","files",["model_file"],["preview"],["normalize_scale"],["chain"],["credits_breakdown"]}` — with `--then`, `credits_consumed` is the **total** for the run and `credits_breakdown` itemizes every task (`[{task_id,type,credits_consumed}]`, generation first)
|
|
97
|
+
- Output JSON: `{"task_id","type","status","credits_consumed","output_dir","files",["model_file"],["source_model_file"],["preview"],["normalize_scale"],["chain"],["credits_breakdown"]}` — with `--then`, `credits_consumed` is the **total** for the run and `credits_breakdown` itemizes every task (`[{task_id,type,credits_consumed}]`, generation first)
|
|
74
98
|
- `normalize_scale` appears when the input was a model file / URL: the import rescaled it (final size = original size × normalize_scale; `1` = untouched) and nothing scales it back — divide by it to recover the original size
|
|
75
99
|
|
|
76
100
|
## Pipes (composing steps yourself)
|
|
@@ -81,23 +105,26 @@ Downstream commands read the upstream task from stdin:
|
|
|
81
105
|
tripo make cat.png --json | tripo anim rig --json | tripo anim retarget --param animation=preset:walk --json
|
|
82
106
|
```
|
|
83
107
|
|
|
108
|
+
If an upstream command fails or prints no task, the downstream submits nothing and exits with the upstream's exit code (or 2). Without a terminal on stdin, process commands never fall back to `@last`; pass the input explicitly.
|
|
109
|
+
|
|
84
110
|
## Other commands
|
|
85
111
|
|
|
86
112
|
| command | purpose |
|
|
87
113
|
| --- | --- |
|
|
88
114
|
| `tripo task get/watch <id> --download` | inspect / block on / download an existing task |
|
|
89
115
|
| `tripo balance` / `tripo usage` | credits: `{"balance","frozen"}` / recent spend |
|
|
116
|
+
| `tripo models` | accepted model ids per capability, defaults and aliases (local, no API call) |
|
|
90
117
|
| `tripo redo [@last]` | same request, new seed |
|
|
91
118
|
| `tripo view [@last]` | (humans) open a local 3D preview; agents read `preview.png` instead |
|
|
92
119
|
| `tripo files upload <path>` | get a `file_token` |
|
|
93
|
-
| `tripo batch run manifest.yaml` | bulk jobs, resumable |
|
|
120
|
+
| `tripo batch run manifest.yaml` | bulk jobs, resumable; no plan card, so estimate and confirm first (`commands/batch` § Cost) |
|
|
94
121
|
| `tripo mcp` | run as an MCP server (tools: tripo_make, tripo_task_get, tripo_task_wait, tripo_balance, tripo_history) |
|
|
95
122
|
| `tripo docs --topic commands/<name>` | print detailed docs for any command |
|
|
96
123
|
|
|
97
124
|
## Detailed docs in this package
|
|
98
125
|
|
|
99
126
|
- `commands/` — one file per command with every flag and parameter
|
|
100
|
-
- model versions · H series (`tripo-v3.x`) · P series (`tripo-p1`, `tripo-p2`
|
|
127
|
+
- model versions · H series (`tripo-v3.x`) · P series (`tripo-p1`, `tripo-p2`) · alias → wire value · GA / Legacy status · quad → `commands/generate` § "Models & Versions" (also the P Series endpoint entry points)
|
|
101
128
|
- `examples/` — copy-paste recipes per scenario (game/print/animation/...)
|
|
102
129
|
- `common-errors.md` — error table with fixes
|
|
103
130
|
|
|
@@ -54,7 +54,7 @@ tripo config context default_scenario=game-mobile output_dir=./assets # per-di
|
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
Env overrides: `TRIPO_API_KEY` `TRIPO_PROFILE` `TRIPO_REGION` `TRIPO_API_BASE_URL` `TRIPO_LLM_BASE_URL` `TRIPO_LLM_API_KEY` `TRIPO_LLM_MODEL`.
|
|
57
|
-
`region`/`api_base_url`/`platform_base_url` are stored per profile; `
|
|
57
|
+
`region`/`api_base_url`/`platform_base_url` are stored per profile; `llm.*`/`default_output_dir` are shared.
|
|
58
58
|
|
|
59
59
|
## tripo doctor
|
|
60
60
|
|
package/skill/commands/batch.md
CHANGED
|
@@ -26,8 +26,18 @@ jobs:
|
|
|
26
26
|
params: { texture_quality: detailed }
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
## Cost
|
|
30
|
+
|
|
31
|
+
- Every job is a full `make` that runs without a plan card or confirmation.
|
|
32
|
+
- The five P2 presets (`game-mobile` `game-pc` `ar-web` `anim` `toy`) cost 100–130 credits per job for the generation step alone; the example's default `game-mobile` is at least 110 per job, before chain steps.
|
|
33
|
+
- Before running, dry-run one job per preset/params combination with the matching `make` flags (`tripo make "a bronze sword" --for game-mobile --then texture,convert:fbx --dry-run --json`), multiply `generation_credits_estimate` by the number of jobs that share it (`null` means not estimated, never zero), relay the total to the human and get confirmation.
|
|
34
|
+
|
|
29
35
|
## Behavior
|
|
30
36
|
|
|
31
|
-
- State is saved next to the manifest (`assets.yaml.state.json`) after every job. Re-running the same command **skips succeeded jobs** (resume). `--fresh` starts over.
|
|
32
|
-
-
|
|
33
|
-
-
|
|
37
|
+
- State is saved next to the manifest (`assets.yaml.state.json`) after every job and as soon as each paid task is created. Re-running the same command **skips succeeded jobs** (resume). `--fresh` starts over.
|
|
38
|
+
- A job is retried (up to `--retries` times) only when the failed attempt left no paid task behind: it failed before anything was submitted, or its only task failed server-side (failed/cancelled tasks are refunded).
|
|
39
|
+
- Anything else stops the job as `needs_attention`, and it is **never resubmitted automatically**, not even on re-run: a create request whose response was lost (the task may exist and be billed), a timeout, a failed artifact download, or a failure after an earlier task of the job succeeded.
|
|
40
|
+
- Its state entry records `tasks` (every task created for the job, in order), `error`, and `suggestion` (the next step, e.g. `tripo task get <id> --download`, or `tripo make <task_id> --then ...` to continue from the last successful task).
|
|
41
|
+
- To resubmit a `needs_attention` job on purpose, delete its entry from the state file, or use `--fresh` to rerun everything.
|
|
42
|
+
- Exit code 6 if any job stays `failed` or `needs_attention`.
|
|
43
|
+
- Final stdout JSON: `{"total","success","failed","needs_attention","state_file","jobs":{...}}`.
|
|
@@ -14,12 +14,12 @@ tripo generate multiview-to-model @last # reuse the 4 views of an image
|
|
|
14
14
|
|
|
15
15
|
### P Series (`tripo-p1` / `tripo-p2`) — same endpoints, different model
|
|
16
16
|
|
|
17
|
-
The P series (low-poly
|
|
17
|
+
The P series (editable low-poly topology) uses the **same three endpoints**; only the `model` value changes. The official docs document it as a separate "P Series" tab on each generation page — this is the direct entry point:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
tripo generate text-to-model "a low poly knight
|
|
21
|
-
tripo generate image-to-model photo.png --model tripo-p2 -p quad=true -p face_limit=12000 # → model: P2-20260801
|
|
22
|
-
tripo generate multiview-to-model front.png back.png --model tripo-p1
|
|
20
|
+
tripo generate text-to-model "a low poly knight for a game" -p face_limit=8000 # → model: P2-20260801
|
|
21
|
+
tripo generate image-to-model photo.png --model tripo-p2 -p quad=true -p face_limit=12000 # → model: P2-20260801
|
|
22
|
+
tripo generate multiview-to-model front.png back.png --model tripo-p1 # explicit lower-cost P-series choice
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
| endpoint | H series (standard) page | P series page |
|
|
@@ -32,17 +32,25 @@ tripo generate multiview-to-model front.png back.png --model tripo-p1
|
|
|
32
32
|
|
|
33
33
|
### 3D models (`--model`) — Models & Versions
|
|
34
34
|
|
|
35
|
-
Keywords: model versions · H series (v3.x) · P series (P1 / P2) ·
|
|
35
|
+
Keywords: model versions · H series (v3.x) · P series (P1 / P2) · quad · alias → wire value.
|
|
36
36
|
|
|
37
37
|
| alias (what you type) | wire value (what the API receives) | status | positioning | notes |
|
|
38
38
|
| --- | --- | --- | --- | --- |
|
|
39
|
-
| `tripo-v3.1`
|
|
40
|
-
| `tripo-p1` | `P1-20260311` | GA |
|
|
41
|
-
| `tripo-p2` | `P2-20260801` |
|
|
39
|
+
| `tripo-v3.1` | `v3.1-20260211` | GA | official default flagship model; dense geometry, H-only topology features, film / print | full feature set; 10–40 credits (text) or 20–50 (image / multiview) by texture tier, plus `geometry_quality=detailed` +20, `quad` +5, `smart_low_poly` +10, `generate_parts` +20 |
|
|
40
|
+
| `tripo-p1` | `P1-20260311` | GA | explicit lower-cost low-poly choice | face_limit 50–20000; **no** `quad` `smart_low_poly` `generate_parts` `geometry_quality`; no published price, so plans leave it unestimated |
|
|
41
|
+
| `tripo-p2` | `P2-20260801` | GA (2026-08) | automatic choice for real-time, game, editable, low-poly, voxel, quad, or a face budget within P2's range | adds `quad` (forces FBX); face_limit 48–50000 tri / 48–25000 quad (validated locally); still **no** `smart_low_poly` `generate_parts` `geometry_quality` (stripped with a warning). 100–130 credits for every input by texture tier, no add-ons; confirm the plan card's estimate with the human before spending |
|
|
42
42
|
| `tripo-v3.0` / `tripo-v2.5` | `v3.0-20250812` / `v2.5-20250123` | Legacy | previous generations | only when the human asks |
|
|
43
43
|
|
|
44
44
|
**Alias vs wire value.** `tripo-*`, `p1`, `p2`, `v3.1` … are CLI-side aliases; the CLI always sends the dated wire value in the `model` field (`--model tripo-p2` → `"model": "P2-20260801"`). The v3 server whitelist accepts wire values only — sending an alias straight to the API returns 1004 `invalid model` with the allowed list. `task.json` records the wire value that was actually used. `tripo-turbo` / `tripo-v2.0` appear in some docs but are **not** on the v3 whitelist (400).
|
|
45
45
|
|
|
46
|
+
**Automatic routing.**
|
|
47
|
+
|
|
48
|
+
- Explicit `--model` always wins, followed by `-p model=<string>`; both are normalized and checked against the selected model's capabilities.
|
|
49
|
+
- With neither form, dense/high-poly geometry, `smart_low_poly=true`, `generate_parts=true`, any explicit `geometry_quality`, and a face budget outside P2's range (below 48, above 50000, or above 25000 with quad) select H3.1 first.
|
|
50
|
+
- A scenario preset is the next preference and outranks prompt hints: film and print use H3.1, while game-mobile, game-pc, ar-web, anim, and toy use P2.
|
|
51
|
+
- Without a preset, real-time/game/editable/topology hints, low-poly/voxel intent, `quad=true`, or a face budget within P2's range select P2.
|
|
52
|
+
- Everything else uses H3.1, the official default model.
|
|
53
|
+
|
|
46
54
|
Official docs (ov / cn):
|
|
47
55
|
- Models & Versions: <https://developers.tripo3d.ai/en/docs/models-and-versions> · <https://developers.tripo3d.com/zh/docs/models-and-versions>
|
|
48
56
|
- P Series model detail: <https://developers.tripo3d.ai/en/models/p1> · <https://developers.tripo3d.com/zh/models/p1>
|
|
@@ -111,14 +119,31 @@ tripo generate image-to-splat photo.png # gaussian splat
|
|
|
111
119
|
| `seedream_v4` | ByteDance | GA | text-to-image default (balanced); **not accepted by image-to-image** |
|
|
112
120
|
| `seedream_v5` | ByteDance | GA | image-to-image default; higher quality |
|
|
113
121
|
| `banana` / `banana_pro` / `banana2` | Google | GA | fast / higher quality / latest fast |
|
|
114
|
-
| `chat_image_1`
|
|
122
|
+
| `chat_image_1` | OpenAI | retired 2026-10-23 | rejected locally; explicitly choose a replacement, never auto-resubmit |
|
|
123
|
+
| `chat_image_1.5` | OpenAI | active; retiring 2026-12-01 | remains supported until retirement |
|
|
115
124
|
| `chat_image_2` | OpenAI | GA | GPT, best quality |
|
|
116
125
|
| `chat_image_2.5_flare` / `chat_image_2.5_sunburst` | OpenAI | GA | 2.5 series: flare = speed tier (chat_image_2 quality, much faster); sunburst = refined tier (keeps unedited areas closest to the original) |
|
|
117
126
|
|
|
118
|
-
Image model ids are sent as-is (no alias
|
|
127
|
+
Image model ids are endpoint-whitelisted and sent as-is (no Gemini/display alias mapping). Unknown IDs fail locally. Since 0.8.0 the CLI rejects retired `chat_image_1` without automatic replacement; `chat_image_1.5` remains valid as of 2026-10-27. Full list with retirement dates: <https://developers.tripo3d.ai/en/docs/models-and-versions>.
|
|
119
128
|
|
|
120
129
|
### Image parameters
|
|
121
130
|
|
|
131
|
+
- Since 0.8.0 the CLI validates `model`, `quality`, `background`, `output_format` and known `size` rules on both image endpoints.
|
|
132
|
+
- Image editing preflights these and reference counts (Seedream ≤4, Banana ≤10, Chat Image ≤16) before uploading any local file.
|
|
133
|
+
- Standalone image/multiview-to-model likewise validates known model/face/quad constraints before uploads; text-to-model validates the effective prompt's 1024-character limit.
|
|
134
|
+
- Non-2.5 `background` is removed with an ignored warning (matching the documented server behavior); 2.5 transparency rejects JPEG. `quality=auto` is rejected.
|
|
135
|
+
- Unspecified values remain unspecified; the CLI does not invent provider fields or silently change models.
|
|
136
|
+
|
|
137
|
+
Size rules (official tabs, checked 2026-10-27):
|
|
138
|
+
- `banana`: fixed `1024x1024`, `832x1248`, `1248x832`, `864x1184`, `1184x864`, `896x1152`, `1152x896`, `768x1344`, `1344x768`, `1536x672`. Omitted size is left to the service; the documented default differs from its explicit fixed-size list.
|
|
139
|
+
- `banana_pro`: `1K` / `2K` / `4K` or positive integer `WxH`; no undocumented pixel limits are invented.
|
|
140
|
+
- `banana2`: `0.5K` / `1K` / `2K` / `4K` only.
|
|
141
|
+
- `seedream_v4`: `2K` / `4K`; `seedream_v5`: `2K` / `3K`; explicit `WxH` requires aspect ratio 1:16–16:1. The official MP ranges are rounded (v4 approximately 3.69–16.78 MP; v5 3.69–10.40 MP); exact pixel-count cutoffs are not asserted by the CLI and still require server validation.
|
|
142
|
+
- `chat_image_1.5`: `1024x1024` / `1024x1536` / `1536x1024` / `auto`.
|
|
143
|
+
- `chat_image_2` / 2.5: `auto` or `WxH`, each edge ≤3840 and divisible by 16, long/short ratio ≤3, total pixels 655360–8294400. `1536x864` and `1088x1920` work; `1080x1920` fails locally.
|
|
144
|
+
|
|
145
|
+
3D display aliases `H3.1` / `P1.0` / `P2.0` (plus `P2.0 Preview`, the pre-GA name kept for compatibility) and legacy `H3.0` / `H2.5` map to the same dated IDs and validation as `tripo-v3.1` / `tripo-p1` / `tripo-p2` / `tripo-v3.0` / `tripo-v2.5`; every model alias is case-insensitive. All `face_limit` values must be finite integers. Unknown model names are rejected, not forwarded.
|
|
146
|
+
|
|
122
147
|
| param | default | endpoint | notes |
|
|
123
148
|
| --- | --- | --- | --- |
|
|
124
149
|
| `prompt` | — | t2i (required), i2i | ≤1024 chars; i2i: required unless `template` is set |
|