@xiaohhhh1/canvas-agent 0.4.57 → 0.4.59
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.
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
export declare const FLOW_C_SCRIPT_CHUNK_MAX = 30;
|
|
3
3
|
export declare const FLOW_C_SCRIPT_CHUNK_SIZES: readonly [10, 5, 1];
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* 20 秒在移除中心可确定性补齐的重复视觉/质量字段后,先安全尝试每回合 2 条;
|
|
6
|
+
* 任何结构或截断失败会降级到 1 条。30 秒输出仍更大,继续保持单条。
|
|
7
7
|
*/
|
|
8
|
-
export declare function flowCScriptChunkSizes(durationSeconds: 10 | 20 | 30): readonly [10, 5, 1] | readonly [1];
|
|
9
|
-
/** 将当前缺失 ordinal
|
|
8
|
+
export declare function flowCScriptChunkSizes(durationSeconds: 10 | 20 | 30): readonly [10, 5, 1] | readonly [2, 1] | readonly [1];
|
|
9
|
+
/** 将当前缺失 ordinal 切成受控子批;长视频绝不恢复 30 条大回合。 */
|
|
10
10
|
export declare function flowCScriptChunks(durationSeconds: 10 | 20 | 30, ordinals: number[], size?: number): number[][];
|
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
export const FLOW_C_SCRIPT_CHUNK_MAX = 30;
|
|
3
3
|
export const FLOW_C_SCRIPT_CHUNK_SIZES = [10, 5, 1];
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* 20 秒在移除中心可确定性补齐的重复视觉/质量字段后,先安全尝试每回合 2 条;
|
|
6
|
+
* 任何结构或截断失败会降级到 1 条。30 秒输出仍更大,继续保持单条。
|
|
7
7
|
*/
|
|
8
8
|
export function flowCScriptChunkSizes(durationSeconds) {
|
|
9
9
|
if (durationSeconds === 20)
|
|
10
|
-
return [1];
|
|
10
|
+
return [2, 1];
|
|
11
11
|
if (durationSeconds === 30)
|
|
12
12
|
return [1];
|
|
13
13
|
return FLOW_C_SCRIPT_CHUNK_SIZES;
|
|
14
14
|
}
|
|
15
|
-
/** 将当前缺失 ordinal
|
|
15
|
+
/** 将当前缺失 ordinal 切成受控子批;长视频绝不恢复 30 条大回合。 */
|
|
16
16
|
export function flowCScriptChunks(durationSeconds, ordinals, size = flowCScriptChunkSizes(durationSeconds)[0]) {
|
|
17
17
|
const chunks = [];
|
|
18
18
|
for (let index = 0; index < ordinals.length; index += size)
|
|
@@ -160,6 +160,8 @@ export declare class WorkflowManager {
|
|
|
160
160
|
status: string;
|
|
161
161
|
} & {
|
|
162
162
|
error?: string;
|
|
163
|
+
code?: string;
|
|
164
|
+
resetOrdinals?: unknown;
|
|
163
165
|
}>;
|
|
164
166
|
submitCandidateChunk(idValue: unknown, groupsValue: unknown): Promise<{
|
|
165
167
|
accepted: number;
|
|
@@ -168,6 +170,8 @@ export declare class WorkflowManager {
|
|
|
168
170
|
selectedCandidates: SelectedCandidate[];
|
|
169
171
|
} & {
|
|
170
172
|
error?: string;
|
|
173
|
+
code?: string;
|
|
174
|
+
resetOrdinals?: unknown;
|
|
171
175
|
}>;
|
|
172
176
|
downloadState(): {
|
|
173
177
|
configured: boolean;
|
|
@@ -293,6 +297,9 @@ export declare function terminalScriptChunkError(results: Array<{
|
|
|
293
297
|
error?: string;
|
|
294
298
|
terminal?: boolean;
|
|
295
299
|
}>): string;
|
|
300
|
+
export declare function scriptCreativeReplanOrdinals(results: unknown[]): number[];
|
|
301
|
+
export declare function creativeReplanOrdinals(error: unknown): number[];
|
|
302
|
+
export declare function recordCreativeReplanAttempts(attempts: Map<number, number>, ordinals: number[], limit?: number): void;
|
|
296
303
|
export declare function scriptChunkPrompt(id: string, task: ScriptTask, ordinals: number[]): string;
|
|
297
304
|
export declare function creativeCandidatePrompt(id: string, task: ScriptTask, ordinals: number[]): string;
|
|
298
305
|
/**
|
package/dist/workflow/manager.js
CHANGED
|
@@ -253,6 +253,7 @@ export class WorkflowManager {
|
|
|
253
253
|
record.activeChunks = 0;
|
|
254
254
|
let chunkSizeIndex = 0;
|
|
255
255
|
let candidateChunkSize = 2;
|
|
256
|
+
const creativeReplanAttempts = new Map();
|
|
256
257
|
while (record.receivedOrdinals.length < task.requested_count) {
|
|
257
258
|
task = await this.scriptTask(id);
|
|
258
259
|
const selectedBefore = selectedCandidateOrdinals(task);
|
|
@@ -280,6 +281,22 @@ export class WorkflowManager {
|
|
|
280
281
|
const terminalError = terminalScriptChunkError(results);
|
|
281
282
|
if (terminalError)
|
|
282
283
|
throw new Error(`创意或脚本结构化契约被 Codex 拒绝,已停止自动重试(${terminalError})`);
|
|
284
|
+
const replanOrdinals = scriptCreativeReplanOrdinals(results);
|
|
285
|
+
if (replanOrdinals.length) {
|
|
286
|
+
recordCreativeReplanAttempts(creativeReplanAttempts, replanOrdinals);
|
|
287
|
+
record.message = `中心发现创意骨架重复,正在为 ordinal ${replanOrdinals.join(", ")} 重新选题;已完成脚本保持不变`;
|
|
288
|
+
record.updatedAt = now();
|
|
289
|
+
this.save();
|
|
290
|
+
const replanResults = await Promise.all(replanOrdinals.map((ordinal) => this.runCandidateChunk(id, task, [ordinal], workspace.workspacePath)));
|
|
291
|
+
const replanTerminalError = terminalScriptChunkError(replanResults);
|
|
292
|
+
if (replanTerminalError)
|
|
293
|
+
throw new Error(`创意重新选题被 Codex 拒绝,已停止自动重试(${replanTerminalError})`);
|
|
294
|
+
const replanError = replanResults.find((result) => result.error)?.error;
|
|
295
|
+
if (replanError)
|
|
296
|
+
throw new Error(`创意重新选题失败(${replanError}),请点击重试`);
|
|
297
|
+
chunkSizeIndex = 0;
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
283
300
|
if (record.receivedOrdinals.length > receivedBefore)
|
|
284
301
|
chunkSizeIndex = 0;
|
|
285
302
|
if (selectedCandidateOrdinals(task).length > selectedBefore.length) {
|
|
@@ -306,6 +323,22 @@ export class WorkflowManager {
|
|
|
306
323
|
if (terminalError) {
|
|
307
324
|
throw new Error(`本机脚本结构化契约被 Codex 拒绝,已停止自动重试且未提交缺失脚本。请先升级或修复 Canvas Agent,再手动重试(${terminalError})`);
|
|
308
325
|
}
|
|
326
|
+
const replanOrdinals = scriptCreativeReplanOrdinals(results);
|
|
327
|
+
if (replanOrdinals.length) {
|
|
328
|
+
recordCreativeReplanAttempts(creativeReplanAttempts, replanOrdinals);
|
|
329
|
+
record.message = `中心发现创意骨架重复,正在为 ordinal ${replanOrdinals.join(", ")} 重新选题;已完成脚本保持不变`;
|
|
330
|
+
record.updatedAt = now();
|
|
331
|
+
this.save();
|
|
332
|
+
const replanResults = await Promise.all(replanOrdinals.map((ordinal) => this.runCandidateChunk(id, task, [ordinal], workspace.workspacePath)));
|
|
333
|
+
const replanTerminalError = terminalScriptChunkError(replanResults);
|
|
334
|
+
if (replanTerminalError)
|
|
335
|
+
throw new Error(`创意重新选题被 Codex 拒绝,已停止自动重试(${replanTerminalError})`);
|
|
336
|
+
const replanError = replanResults.find((result) => result.error)?.error;
|
|
337
|
+
if (replanError)
|
|
338
|
+
throw new Error(`创意重新选题失败(${replanError}),请点击重试`);
|
|
339
|
+
chunkSizeIndex = 0;
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
309
342
|
const progressed = record.receivedOrdinals.length > before;
|
|
310
343
|
if (progressed) {
|
|
311
344
|
chunkSizeIndex = 0;
|
|
@@ -396,7 +429,11 @@ export class WorkflowManager {
|
|
|
396
429
|
return { terminal: false };
|
|
397
430
|
}
|
|
398
431
|
catch (error) {
|
|
399
|
-
return {
|
|
432
|
+
return {
|
|
433
|
+
error: error instanceof Error ? `结构化脚本未通过本机校验:${error.message}` : "结构化脚本未通过本机校验",
|
|
434
|
+
terminal: false,
|
|
435
|
+
replanOrdinals: creativeReplanOrdinals(error),
|
|
436
|
+
};
|
|
400
437
|
}
|
|
401
438
|
}
|
|
402
439
|
/** 只记录阶段、ordinal 和毫秒数;禁止记录 prompt、令牌或中心能力。 */
|
|
@@ -572,6 +609,23 @@ export function compareScriptQueueRecords(left, right) {
|
|
|
572
609
|
export function terminalScriptChunkError(results) {
|
|
573
610
|
return results.find((result) => result.terminal)?.error || "";
|
|
574
611
|
}
|
|
612
|
+
export function scriptCreativeReplanOrdinals(results) {
|
|
613
|
+
return [...new Set(results.flatMap((result) => (result && typeof result === "object" ? result.replanOrdinals || [] : [])).filter((ordinal) => Number.isInteger(ordinal) && ordinal > 0))].sort((left, right) => left - right);
|
|
614
|
+
}
|
|
615
|
+
export function creativeReplanOrdinals(error) {
|
|
616
|
+
if (!error || typeof error !== "object" || error.code !== "FLOW_C_CREATIVE_REPLAN_REQUIRED")
|
|
617
|
+
return [];
|
|
618
|
+
const values = error.resetOrdinals;
|
|
619
|
+
return Array.isArray(values) ? [...new Set(values.map(Number).filter((ordinal) => Number.isInteger(ordinal) && ordinal > 0))].sort((left, right) => left - right) : [];
|
|
620
|
+
}
|
|
621
|
+
export function recordCreativeReplanAttempts(attempts, ordinals, limit = 3) {
|
|
622
|
+
for (const ordinal of ordinals) {
|
|
623
|
+
const next = Number(attempts.get(ordinal) || 0) + 1;
|
|
624
|
+
attempts.set(ordinal, next);
|
|
625
|
+
if (next > limit)
|
|
626
|
+
throw new Error(`ordinal ${ordinal} 已重新选题 ${limit} 次仍与已完成脚本重复,已停止避免无效循环`);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
575
629
|
class ExpiredCapabilityError extends Error {
|
|
576
630
|
}
|
|
577
631
|
export function scriptChunkPrompt(id, task, ordinals) {
|
|
@@ -595,7 +649,7 @@ ${durationRules}
|
|
|
595
649
|
3. 每段永远是独立 0–10 秒,含 1–8 个按剧情需要决定的 shots、准确 voiceover、onScreenText、evidence、soundBgm、emotionalNote 与 endingState;模型不要输出 continuity 或 continuityMode。
|
|
596
650
|
4. shot.visual 要直接写出主体位置、景别、光线、材质、动作峰值和当地自然环境,并保留真实皮肤、细发、布料/商品微纹理和实景混合光;禁止塑料蜡感、静态举产品、品牌广告片、电视购物或伪造工厂/销量/来源。
|
|
597
651
|
5. 20/30 秒的后一段剧情承接前段 endingState,但每段仍只使用自己的局部 0–10 秒执行内容。
|
|
598
|
-
6. creativePlan
|
|
652
|
+
6. creativePlan 只写 format、visualHook、conflict、escalation/turn、productIntervention、visibleProof、callbackMotivation 与 differentiationKey。Agent 会把选中卡的构图、材质、光线、文化、真实性边界和 fingerprint 确定性并回,中心会程序化计算质量门;模型不要重复这些字段。
|
|
599
653
|
固定使用 GPT-5.6 Terra 高推理。storyboardLayoutVersion=${layoutVersion} 仅由中心管理。只返回当前结构化 jobs,不调用工具、不创建任何图片或视频任务。`;
|
|
600
654
|
}
|
|
601
655
|
export function creativeCandidatePrompt(id, task, ordinals) {
|
|
@@ -765,8 +819,13 @@ async function commerceJson(url, token, tokenHeader, init = {}) {
|
|
|
765
819
|
headers.set("content-type", "application/json");
|
|
766
820
|
const response = await fetch(url, { ...init, headers, signal: AbortSignal.timeout(120_000) });
|
|
767
821
|
const body = await response.json().catch(() => ({}));
|
|
768
|
-
if (!response.ok)
|
|
769
|
-
|
|
822
|
+
if (!response.ok) {
|
|
823
|
+
const error = new Error(body.error || `中心接口返回 ${response.status}`);
|
|
824
|
+
error.status = response.status;
|
|
825
|
+
error.code = body.code;
|
|
826
|
+
error.resetOrdinals = body.resetOrdinals;
|
|
827
|
+
throw error;
|
|
828
|
+
}
|
|
770
829
|
return body;
|
|
771
830
|
}
|
|
772
831
|
function loadState() {
|
|
@@ -26,37 +26,16 @@ function creativePlanSchema() {
|
|
|
26
26
|
const properties = {
|
|
27
27
|
format: text,
|
|
28
28
|
visualHook: text,
|
|
29
|
-
firstFrameFocus: text,
|
|
30
|
-
visualContrast: text,
|
|
31
|
-
sensoryTexture: text,
|
|
32
|
-
motionPeak: text,
|
|
33
|
-
compositionLighting: text,
|
|
34
|
-
localNativeDetail: text,
|
|
35
|
-
antiFlatness: text,
|
|
36
29
|
conflict: text,
|
|
37
30
|
escalation: nullableText,
|
|
38
31
|
turn: nullableText,
|
|
39
32
|
productIntervention: text,
|
|
40
33
|
visibleProof: text,
|
|
41
34
|
callbackMotivation: text,
|
|
42
|
-
truthBoundary: text,
|
|
43
35
|
differentiationKey: text,
|
|
44
|
-
styleCardSummary: nullableText,
|
|
45
36
|
};
|
|
46
37
|
return object(properties);
|
|
47
38
|
}
|
|
48
|
-
function qualityGateSchema() {
|
|
49
|
-
return object({
|
|
50
|
-
hook: text,
|
|
51
|
-
conflict: text,
|
|
52
|
-
escalationOrTurn: text,
|
|
53
|
-
productIntervention: text,
|
|
54
|
-
visibleProof: text,
|
|
55
|
-
callbackMotivation: text,
|
|
56
|
-
truthBoundary: text,
|
|
57
|
-
batchDifferentiation: text,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
39
|
function segmentSchema() {
|
|
61
40
|
return object({
|
|
62
41
|
voiceCue: text,
|
|
@@ -86,7 +65,6 @@ export function flowCScriptOutputSchema(durationSeconds, count) {
|
|
|
86
65
|
sellingFormId: text,
|
|
87
66
|
creativePlan: creativePlanSchema(),
|
|
88
67
|
voiceProfile: voiceProfileSchema(),
|
|
89
|
-
qualityGate: qualityGateSchema(),
|
|
90
68
|
openingState: openingStateSchema(),
|
|
91
69
|
};
|
|
92
70
|
if (durationSeconds === 10)
|