@pippit-dev/cli 1.0.43 → 1.0.45
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/checksums.txt +6 -6
- package/cmd/auth/auth_test.go +1 -1
- package/dist/checksums.txt +6 -6
- package/internal/auth/auth_test.go +21 -17
- package/internal/auth/loopback_origins_test.go +1 -1
- package/internal/auth/manager.go +1 -1
- package/internal/common/upload_file.go +2 -2
- package/internal/config/config.go +1 -0
- package/internal/generate_image/generate_image.go +4 -4
- package/internal/generate_video/generate_video.go +10 -10
- package/package.json +1 -1
- package/skills/xyq-nest-skill/SKILL.md +2 -0
package/checksums.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
3802437e93dcd395df47e4e735a8a4b958528f76ea64d672cd3fa3cb719fd163 pippit-tool-cli-1.0.45-darwin-amd64.tar.gz
|
|
2
|
+
b80b030e77b0fbdffb0b05c8a38fdc5c939d01ca69cb1ab6d2c0bd0c1e236892 pippit-tool-cli-1.0.45-darwin-arm64.tar.gz
|
|
3
|
+
33095e1ceec2220ea1b79abfa56948dd5d237c1831ab2437c8af064d00db7c99 pippit-tool-cli-1.0.45-linux-amd64.tar.gz
|
|
4
|
+
85a91aeae7b9ea1324a8aee1be576fad12297cecdfe2828851147d50f4dbc177 pippit-tool-cli-1.0.45-linux-arm64.tar.gz
|
|
5
|
+
e93240dbc814104ea278197aff983c2491089be1b9fe55f216007b1a612c7f93 pippit-tool-cli-1.0.45-windows-amd64.zip
|
|
6
|
+
d5f196ea5b5f466911573a1177702ad00f27da153d2f29b5b1e65cd60f7f5100 pippit-tool-cli-1.0.45-windows-arm64.zip
|
package/cmd/auth/auth_test.go
CHANGED
|
@@ -75,7 +75,7 @@ func (manager *fakeAuthManager) CredentialScope(context.Context) (string, error)
|
|
|
75
75
|
|
|
76
76
|
func TestLoginCommandPrintsMetadataWithoutAccessKey(t *testing.T) {
|
|
77
77
|
const accessKey = "must-never-be-printed"
|
|
78
|
-
const loginURL = "https://
|
|
78
|
+
const loginURL = "https://www.xiaoyunque.com/cli/pippit-tool-login?callback=http%3A%2F%2F127.0.0.1%3A1234&random_secret_key=one-time-secret"
|
|
79
79
|
expiresAt := time.Now().Add(time.Hour).Unix()
|
|
80
80
|
manager := &fakeAuthManager{credential: &internal_auth.Credential{
|
|
81
81
|
AccessKey: accessKey, UID: "123", CredentialScope: "device-scope", ExpiredAt: expiresAt,
|
package/dist/checksums.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
3802437e93dcd395df47e4e735a8a4b958528f76ea64d672cd3fa3cb719fd163 pippit-tool-cli-1.0.45-darwin-amd64.tar.gz
|
|
2
|
+
b80b030e77b0fbdffb0b05c8a38fdc5c939d01ca69cb1ab6d2c0bd0c1e236892 pippit-tool-cli-1.0.45-darwin-arm64.tar.gz
|
|
3
|
+
33095e1ceec2220ea1b79abfa56948dd5d237c1831ab2437c8af064d00db7c99 pippit-tool-cli-1.0.45-linux-amd64.tar.gz
|
|
4
|
+
85a91aeae7b9ea1324a8aee1be576fad12297cecdfe2828851147d50f4dbc177 pippit-tool-cli-1.0.45-linux-arm64.tar.gz
|
|
5
|
+
e93240dbc814104ea278197aff983c2491089be1b9fe55f216007b1a612c7f93 pippit-tool-cli-1.0.45-windows-amd64.zip
|
|
6
|
+
d5f196ea5b5f466911573a1177702ad00f27da153d2f29b5b1e65cd60f7f5100 pippit-tool-cli-1.0.45-windows-arm64.zip
|
|
@@ -96,7 +96,7 @@ func (s *memoryCredentialStore) Delete(ctx context.Context) error {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
func TestBrowserFlowUsesDedicatedPageAndStrictBoundCallback(t *testing.T) {
|
|
99
|
-
authURL, _ := url.Parse(config.
|
|
99
|
+
authURL, _ := url.Parse(config.DefaultAuthBaseURL)
|
|
100
100
|
deviceID, _ := randomEncoded(bytes.NewReader(bytes.Repeat([]byte{0x21}, deviceIDBytes)), deviceIDBytes)
|
|
101
101
|
flow, err := startBrowserFlow(
|
|
102
102
|
authURL, bytes.NewReader(bytes.Repeat([]byte{0x42}, 2*randomBindingBytes)),
|
|
@@ -111,7 +111,7 @@ func TestBrowserFlowUsesDedicatedPageAndStrictBoundCallback(t *testing.T) {
|
|
|
111
111
|
if err != nil {
|
|
112
112
|
t.Fatal(err)
|
|
113
113
|
}
|
|
114
|
-
if loginURL.Scheme+"://"+loginURL.Host != config.
|
|
114
|
+
if loginURL.Scheme+"://"+loginURL.Host != config.DefaultAuthBaseURL || loginURL.Path != loginPagePath {
|
|
115
115
|
t.Fatalf("login URL target = %s://%s%s", loginURL.Scheme, loginURL.Host, loginURL.Path)
|
|
116
116
|
}
|
|
117
117
|
query := loginURL.Query()
|
|
@@ -152,30 +152,30 @@ func TestBrowserFlowUsesDedicatedPageAndStrictBoundCallback(t *testing.T) {
|
|
|
152
152
|
}
|
|
153
153
|
wrongSecret := payload
|
|
154
154
|
wrongSecret.RandomSecretKey = "wrong-secret"
|
|
155
|
-
if status := sendCallback(t, callbackURL, config.
|
|
155
|
+
if status := sendCallback(t, callbackURL, config.DefaultAuthBaseURL, wrongSecret); status != http.StatusBadRequest {
|
|
156
156
|
t.Fatalf("wrong secret status = %d", status)
|
|
157
157
|
}
|
|
158
|
-
if status := postRawCallback(t, callbackURL, config.
|
|
158
|
+
if status := postRawCallback(t, callbackURL, config.DefaultAuthBaseURL, `{"type":"access_key","unknown":true}`); status != http.StatusBadRequest {
|
|
159
159
|
t.Fatalf("unknown field status = %d", status)
|
|
160
160
|
}
|
|
161
|
-
if status := sendCallback(t, callbackURL+"&state=duplicate", config.
|
|
161
|
+
if status := sendCallback(t, callbackURL+"&state=duplicate", config.DefaultAuthBaseURL, payload); status != http.StatusBadRequest {
|
|
162
162
|
t.Fatalf("duplicate state status = %d", status)
|
|
163
163
|
}
|
|
164
|
-
if status := sendCallback(t, callbackURL+"&unexpected=value", config.
|
|
164
|
+
if status := sendCallback(t, callbackURL+"&unexpected=value", config.DefaultAuthBaseURL, payload); status != http.StatusBadRequest {
|
|
165
165
|
t.Fatalf("unexpected transport query status = %d", status)
|
|
166
166
|
}
|
|
167
|
-
if status := sendPreflight(t, callbackURL, config.
|
|
167
|
+
if status := sendPreflight(t, callbackURL, config.DefaultAuthBaseURL); status != http.StatusNoContent {
|
|
168
168
|
t.Fatalf("preflight status = %d", status)
|
|
169
169
|
}
|
|
170
170
|
securityRuntimeCallback := callbackURL + "&a_bogus=signed-request&msToken=transport-token"
|
|
171
|
-
if status := sendCallback(t, securityRuntimeCallback, config.
|
|
171
|
+
if status := sendCallback(t, securityRuntimeCallback, config.DefaultAuthBaseURL, payload); status != http.StatusOK {
|
|
172
172
|
t.Fatalf("security-runtime callback status = %d", status)
|
|
173
173
|
}
|
|
174
174
|
got, err := flow.wait(context.Background())
|
|
175
175
|
if err != nil || got.AccessKey != payload.AccessKey || got.UID != payload.UID || got.TokenID != payload.TokenID {
|
|
176
176
|
t.Fatalf("callback payload = %#v, %v", credentialPayloadWithoutSecret(got), err)
|
|
177
177
|
}
|
|
178
|
-
if status := sendCallback(t, callbackURL, config.
|
|
178
|
+
if status := sendCallback(t, callbackURL, config.DefaultAuthBaseURL, payload); status != http.StatusConflict {
|
|
179
179
|
t.Fatalf("replayed callback status = %d", status)
|
|
180
180
|
}
|
|
181
181
|
}
|
|
@@ -185,6 +185,7 @@ func TestManagerLoginStoresPageIssuedCredentialWithoutServerExchange(t *testing.
|
|
|
185
185
|
store := &memoryCredentialStore{}
|
|
186
186
|
cfg := config.Load()
|
|
187
187
|
cfg.AccessKey = ""
|
|
188
|
+
cfg.BaseURL = "https://untrusted.invalid"
|
|
188
189
|
manager := NewManager(
|
|
189
190
|
cfg,
|
|
190
191
|
WithCredentialStore(store),
|
|
@@ -204,6 +205,9 @@ func TestManagerLoginStoresPageIssuedCredentialWithoutServerExchange(t *testing.
|
|
|
204
205
|
if parseErr != nil {
|
|
205
206
|
return parseErr
|
|
206
207
|
}
|
|
208
|
+
if loginURL.Scheme != "https" || loginURL.Host != "www.xiaoyunque.com" {
|
|
209
|
+
t.Errorf("login origin = %s://%s, want https://www.xiaoyunque.com", loginURL.Scheme, loginURL.Host)
|
|
210
|
+
}
|
|
207
211
|
if loginURL.Path != loginPagePath || loginURL.Query().Get("force") != "" {
|
|
208
212
|
return fmt.Errorf("unexpected login URL")
|
|
209
213
|
}
|
|
@@ -218,7 +222,7 @@ func TestManagerLoginStoresPageIssuedCredentialWithoutServerExchange(t *testing.
|
|
|
218
222
|
Source: loginSource,
|
|
219
223
|
CallbackURL: loginURL.Query().Get("callback"),
|
|
220
224
|
}
|
|
221
|
-
if status := sendCallback(t, payload.CallbackURL,
|
|
225
|
+
if status := sendCallback(t, payload.CallbackURL, loginURL.Scheme+"://"+loginURL.Host, payload); status != http.StatusOK {
|
|
222
226
|
return fmt.Errorf("callback status %d", status)
|
|
223
227
|
}
|
|
224
228
|
return nil
|
|
@@ -273,7 +277,7 @@ func TestManagerWaitsForCallbackWhenBrowserOpenFails(t *testing.T) {
|
|
|
273
277
|
Source: loginSource,
|
|
274
278
|
CallbackURL: loginURL.Query().Get("callback"),
|
|
275
279
|
}
|
|
276
|
-
if status := sendCallback(t, payload.CallbackURL, config.
|
|
280
|
+
if status := sendCallback(t, payload.CallbackURL, config.DefaultAuthBaseURL, payload); status != http.StatusOK {
|
|
277
281
|
return fmt.Errorf("callback status %d", status)
|
|
278
282
|
}
|
|
279
283
|
return errors.New("browser opener unavailable")
|
|
@@ -347,7 +351,7 @@ func TestManagerReauthenticationPinsAccountAndRequiresRotation(t *testing.T) {
|
|
|
347
351
|
}
|
|
348
352
|
|
|
349
353
|
func TestBrowserFlowRequiresExpectedAccountForForceAndNeverUsesRawUID(t *testing.T) {
|
|
350
|
-
authURL, _ := url.Parse(config.
|
|
354
|
+
authURL, _ := url.Parse(config.DefaultAuthBaseURL)
|
|
351
355
|
deviceID, _ := randomEncoded(bytes.NewReader(bytes.Repeat([]byte{0x22}, deviceIDBytes)), deviceIDBytes)
|
|
352
356
|
if _, err := startBrowserFlow(
|
|
353
357
|
authURL, bytes.NewReader(bytes.Repeat([]byte{0x42}, 2*randomBindingBytes)),
|
|
@@ -378,7 +382,7 @@ func TestBrowserFlowRequiresExpectedAccountForForceAndNeverUsesRawUID(t *testing
|
|
|
378
382
|
}
|
|
379
383
|
|
|
380
384
|
func TestBrowserFlowSendsStoredTokenIDOnNormalLogin(t *testing.T) {
|
|
381
|
-
authURL, _ := url.Parse(config.
|
|
385
|
+
authURL, _ := url.Parse(config.DefaultAuthBaseURL)
|
|
382
386
|
deviceID, _ := randomEncoded(bytes.NewReader(bytes.Repeat([]byte{0x23}, deviceIDBytes)), deviceIDBytes)
|
|
383
387
|
flow, err := startBrowserFlow(
|
|
384
388
|
authURL, bytes.NewReader(bytes.Repeat([]byte{0x44}, 2*randomBindingBytes)),
|
|
@@ -398,7 +402,7 @@ func TestBrowserFlowSendsStoredTokenIDOnNormalLogin(t *testing.T) {
|
|
|
398
402
|
}
|
|
399
403
|
|
|
400
404
|
func TestBrowserFlowAllowsLogoutIdentityTokenWithoutAccountBinding(t *testing.T) {
|
|
401
|
-
authURL, _ := url.Parse(config.
|
|
405
|
+
authURL, _ := url.Parse(config.DefaultAuthBaseURL)
|
|
402
406
|
deviceID, _ := randomEncoded(bytes.NewReader(bytes.Repeat([]byte{0x24}, deviceIDBytes)), deviceIDBytes)
|
|
403
407
|
flow, err := startBrowserFlow(
|
|
404
408
|
authURL, bytes.NewReader(bytes.Repeat([]byte{0x45}, 2*randomBindingBytes)),
|
|
@@ -464,7 +468,7 @@ func TestManagerDerivesExpectedAccountFromDurableScope(t *testing.T) {
|
|
|
464
468
|
Source: loginSource,
|
|
465
469
|
CallbackURL: loginURL.Query().Get("callback"),
|
|
466
470
|
}
|
|
467
|
-
if status := sendCallback(t, payload.CallbackURL, config.
|
|
471
|
+
if status := sendCallback(t, payload.CallbackURL, config.DefaultAuthBaseURL, payload); status != http.StatusOK {
|
|
468
472
|
return fmt.Errorf("callback status %d", status)
|
|
469
473
|
}
|
|
470
474
|
return nil
|
|
@@ -488,7 +492,7 @@ func TestResolveStatusLogoutAndAuthOrigin(t *testing.T) {
|
|
|
488
492
|
cfg.AccessKey = " env-ak "
|
|
489
493
|
cfg.BaseURL = "https://untrusted.invalid"
|
|
490
494
|
manager := NewManager(cfg, WithCredentialStore(store), withClockForTest(func() time.Time { return fixedNow }))
|
|
491
|
-
if manager.authBaseURL.String() != config.
|
|
495
|
+
if manager.authBaseURL.String() != config.DefaultAuthBaseURL {
|
|
492
496
|
t.Fatalf("browser login followed runtime business base URL: %q", manager.authBaseURL)
|
|
493
497
|
}
|
|
494
498
|
if key, err := manager.ResolveAccessKey(context.Background()); err != nil || key != "env-ak" {
|
|
@@ -738,7 +742,7 @@ func callbackOpener(t *testing.T, expiry time.Time, uid, tokenID, accessKey stri
|
|
|
738
742
|
Source: loginSource,
|
|
739
743
|
CallbackURL: loginURL.Query().Get("callback"),
|
|
740
744
|
}
|
|
741
|
-
if status := sendCallback(t, payload.CallbackURL, config.
|
|
745
|
+
if status := sendCallback(t, payload.CallbackURL, config.DefaultAuthBaseURL, payload); status != http.StatusOK {
|
|
742
746
|
return fmt.Errorf("callback status %d", status)
|
|
743
747
|
}
|
|
744
748
|
return nil
|
|
@@ -16,7 +16,7 @@ import (
|
|
|
16
16
|
|
|
17
17
|
func newOriginTestFlow(t *testing.T) (*browserFlow, accessKeyPayload) {
|
|
18
18
|
t.Helper()
|
|
19
|
-
authURL, _ := url.Parse(config.
|
|
19
|
+
authURL, _ := url.Parse(config.DefaultAuthBaseURL)
|
|
20
20
|
deviceID, _ := randomEncoded(bytes.NewReader(bytes.Repeat([]byte{0x21}, deviceIDBytes)), deviceIDBytes)
|
|
21
21
|
flow, err := startBrowserFlow(authURL, bytes.NewReader(bytes.Repeat([]byte{0x42}, 2*randomBindingBytes)), deviceID, "", "", false)
|
|
22
22
|
if err != nil {
|
package/internal/auth/manager.go
CHANGED
|
@@ -46,7 +46,7 @@ func WithCredentialStore(store CredentialStore) ManagerOption {
|
|
|
46
46
|
// API configuration does not affect the browser identity origin.
|
|
47
47
|
func NewManager(cfg *config.Config, options ...ManagerOption) *Manager {
|
|
48
48
|
serviceName := config.DefaultAuthStoreServiceName
|
|
49
|
-
authBaseURL, _ := url.Parse(config.
|
|
49
|
+
authBaseURL, _ := url.Parse(config.DefaultAuthBaseURL)
|
|
50
50
|
manager := &Manager{
|
|
51
51
|
localCredentialsEnabled: true,
|
|
52
52
|
cfg: cfg,
|
|
@@ -94,12 +94,12 @@ func UploadFile(ctx context.Context, opts UploadFileOptions, runner *Runner) (*U
|
|
|
94
94
|
if resp.Errmsg == "" {
|
|
95
95
|
resp.Errmsg = "未知错误"
|
|
96
96
|
}
|
|
97
|
-
return nil, fmt.
|
|
97
|
+
return nil, NewLogIDError(fmt.Sprintf("上传文件请求返回失败: ret=%s errmsg=%s", resp.Ret, resp.Errmsg), resp.LogID)
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
assetID := strings.TrimSpace(resp.Data.PippitAssetID)
|
|
101
101
|
if assetID == "" {
|
|
102
|
-
return nil,
|
|
102
|
+
return nil, NewLogIDError("上传文件响应缺少 pippit_asset_id", resp.LogID)
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
return &UploadFileResult{
|
|
@@ -60,7 +60,7 @@ func Run(ctx context.Context, opts *Options, runner *common.Runner) (*common.Sub
|
|
|
60
60
|
|
|
61
61
|
imageAssetIDs, err := uploadImageList(ctx, opts.ImagePaths, runner)
|
|
62
62
|
if err != nil {
|
|
63
|
-
return nil,
|
|
63
|
+
return nil, err
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
body := buildSubmitRunBody(opts, modelKey, imageAssetIDs)
|
|
@@ -128,14 +128,14 @@ func SupportedRatioUsage() string {
|
|
|
128
128
|
|
|
129
129
|
func uploadImageList(ctx context.Context, paths []string, runner *common.Runner) ([]string, error) {
|
|
130
130
|
assetIDs := make([]string, 0, len(paths))
|
|
131
|
-
for
|
|
131
|
+
for i, path := range paths {
|
|
132
132
|
expanded, err := common.ExpandPath(path)
|
|
133
133
|
if err != nil {
|
|
134
|
-
return nil, err
|
|
134
|
+
return nil, fmt.Errorf("第%d张参考图片 %q 路径解析失败: %w", i+1, filepath.Base(path), err)
|
|
135
135
|
}
|
|
136
136
|
result, err := common.UploadFile(ctx, common.UploadFileOptions{Path: expanded}, runner)
|
|
137
137
|
if err != nil {
|
|
138
|
-
return nil, err
|
|
138
|
+
return nil, fmt.Errorf("第%d张参考图片 %q 上传失败: %w", i+1, filepath.Base(path), err)
|
|
139
139
|
}
|
|
140
140
|
assetIDs = append(assetIDs, result.AssetID)
|
|
141
141
|
}
|
|
@@ -45,17 +45,17 @@ func Run(ctx context.Context, opts *Options, runner *common.Runner) (*Result, er
|
|
|
45
45
|
return nil, err
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
imageAssetIDs, err := uploadMediaList(ctx, opts.ImagePaths, runner)
|
|
48
|
+
imageAssetIDs, err := uploadMediaList(ctx, "张参考图片", opts.ImagePaths, runner)
|
|
49
49
|
if err != nil {
|
|
50
|
-
return nil,
|
|
50
|
+
return nil, err
|
|
51
51
|
}
|
|
52
|
-
videoAssetIDs, err := uploadMediaList(ctx, opts.VideoPaths, runner)
|
|
52
|
+
videoAssetIDs, err := uploadMediaList(ctx, "个参考视频", opts.VideoPaths, runner)
|
|
53
53
|
if err != nil {
|
|
54
|
-
return nil,
|
|
54
|
+
return nil, err
|
|
55
55
|
}
|
|
56
|
-
audioAssetIDs, err := uploadMediaList(ctx, opts.AudioPaths, runner)
|
|
56
|
+
audioAssetIDs, err := uploadMediaList(ctx, "段参考音频", opts.AudioPaths, runner)
|
|
57
57
|
if err != nil {
|
|
58
|
-
return nil,
|
|
58
|
+
return nil, err
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
body := buildSubmitRunBody(opts, imageAssetIDs, videoAssetIDs, audioAssetIDs)
|
|
@@ -99,16 +99,16 @@ func validateMediaExtensions(kind string, paths []string, allowed map[string]str
|
|
|
99
99
|
return nil
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
func uploadMediaList(ctx context.Context, paths []string, runner *common.Runner) ([]string, error) {
|
|
102
|
+
func uploadMediaList(ctx context.Context, mediaLabel string, paths []string, runner *common.Runner) ([]string, error) {
|
|
103
103
|
assetIDs := make([]string, 0, len(paths))
|
|
104
|
-
for
|
|
104
|
+
for i, path := range paths {
|
|
105
105
|
expanded, err := common.ExpandPath(path)
|
|
106
106
|
if err != nil {
|
|
107
|
-
return nil, err
|
|
107
|
+
return nil, fmt.Errorf("第%d%s %q 路径解析失败: %w", i+1, mediaLabel, filepath.Base(path), err)
|
|
108
108
|
}
|
|
109
109
|
result, err := common.UploadFile(ctx, common.UploadFileOptions{Path: expanded}, runner)
|
|
110
110
|
if err != nil {
|
|
111
|
-
return nil, err
|
|
111
|
+
return nil, fmt.Errorf("第%d%s %q 上传失败: %w", i+1, mediaLabel, filepath.Base(path), err)
|
|
112
112
|
}
|
|
113
113
|
assetIDs = append(assetIDs, result.AssetID)
|
|
114
114
|
}
|
package/package.json
CHANGED
|
@@ -58,6 +58,8 @@ metadata:
|
|
|
58
58
|
- 用户明确要求生成或处理,即可在该范围内执行;仅咨询用法、费用或方案时不提交。范围、必填信息或消耗 credits 的授权不明确时,先确认,不重复索要已给出的授权。
|
|
59
59
|
- 提问优先使用宿主实际提供且当前模式允许的工具:Codex 的 `request_user_input` 或 `request_user_input_async`,WorkBuddy 的 `ask_user_question`;不可用时用普通聊天。需要答案时等待答复。
|
|
60
60
|
- 素材参数接收本地文件路径,CLI 内部上传。远程链接不能冒充本地路径;缺少可访问文件时先解决素材获取。单文件必须小于 500 MB(500000000 字节)。
|
|
61
|
+
- `generate-image` / `generate-video` 上传素材失败时,向用户说明 CLI 返回的素材类型、类型内序号、文件名、原始原因和可用的 LogID,并说明尚未提交生成任务。序号按同类型参数的传入顺序从 1 开始,不是所有附件的混合序号;只有服务端明确返回审核拒绝时才说明审核未通过,不能把网络、权限等失败都归为审核问题。
|
|
62
|
+
- 上传遇到首个失败即停止,后续素材尚未上传,不能宣称它们审核通过。根据失败原因等待用户替换对应素材或解决问题,不自动删减素材、逐个重传排查或重新提交生成。旧 CLI 未返回文件定位时如实说明无法确定具体素材,不凭图片内容猜测。
|
|
61
63
|
- 提交成功后立即展示真实 `web_thread_link`;未返回链接时如实说明,保留任务 ID。后续查询和下载失败不能触发重复生成。
|
|
62
64
|
- 每个最终图片/视频都通过宿主文件交付或媒体渲染能力展示为真实附件或可预览媒体。URL、路径列表仅作补充;详细完成标准见共用交付流程。
|
|
63
65
|
|