@xiaohhhh1/canvas-agent 0.4.57 → 0.4.58

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.
@@ -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
  /**
@@ -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 { error: error instanceof Error ? `结构化脚本未通过本机校验:${error.message}` : "结构化脚本未通过本机校验", terminal: false };
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) {
@@ -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
- throw new Error(body.error || `中心接口返回 ${response.status}`);
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() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiaohhhh1/canvas-agent",
3
- "version": "0.4.57",
3
+ "version": "0.4.58",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",