fix(design): preserve command outcome certainty
This commit is contained in:
@@ -332,6 +332,7 @@ function sendRouteError(res: ServerResponse, error: unknown): void {
|
||||
status: error.status,
|
||||
code: error.code,
|
||||
error: error.message,
|
||||
...(error.commandOutcome ? { commandOutcome: error.commandOutcome } : {}),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type {
|
||||
DesignAsset,
|
||||
DesignAssetUploadInput,
|
||||
DesignCommandFailureOutcome,
|
||||
DesignCommandInput,
|
||||
DesignCommandResult,
|
||||
DesignCreateWorkspaceInput,
|
||||
@@ -20,12 +21,19 @@ export type CloseEventSessionsOptions = {
|
||||
export class DesignWorkspaceModuleError extends Error {
|
||||
readonly status: number;
|
||||
readonly code: string;
|
||||
readonly commandOutcome?: DesignCommandFailureOutcome;
|
||||
|
||||
constructor(status: number, code: string, message: string) {
|
||||
constructor(
|
||||
status: number,
|
||||
code: string,
|
||||
message: string,
|
||||
commandOutcome?: DesignCommandFailureOutcome,
|
||||
) {
|
||||
super(message);
|
||||
this.name = 'DesignWorkspaceModuleError';
|
||||
this.status = status;
|
||||
this.code = code;
|
||||
this.commandOutcome = commandOutcome;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
type DesignAssistantDeltaEvent,
|
||||
type DesignCapabilities,
|
||||
type DesignChangeSet,
|
||||
type DesignCommandFailureOutcome,
|
||||
type DesignCommandInput,
|
||||
type DesignCommandResult,
|
||||
type DesignCompilationIssue,
|
||||
@@ -628,25 +629,87 @@ function userFacingErrorMessage(code: string): string {
|
||||
budget_denied: '当前设计点不足,无法开始生成',
|
||||
policy_blocked: '当前内容不符合创作安全规则',
|
||||
design_reasoner_unavailable: '设计 Agent 暂时不可用,请稍后重试',
|
||||
design_reasoner_invalid: 'AI 没有整理好这次想法,请再试一次',
|
||||
design_agent_run_failed: 'AI 这次没有完成设计整理,请再试一次',
|
||||
design_agent_run_cancelled: '这次设计整理已停止',
|
||||
design_runtime_unavailable: 'AI 设计服务暂时不可用',
|
||||
design_production_unavailable: '当前生成能力暂时不可用',
|
||||
agent_runtime_unavailable: 'AI 设计服务暂时不可用,请稍后重试',
|
||||
agent_command_invalid: '设计请求内容无效,请检查后重试',
|
||||
auth_required: '请先登录后再使用 AI 设计',
|
||||
auth_expired: '登录状态已失效,请重新登录',
|
||||
};
|
||||
return messages[code] ?? 'AI 设计请求失败,请稍后重试';
|
||||
return messages[code.toLowerCase()] ?? 'AI 设计请求失败,请稍后重试';
|
||||
}
|
||||
|
||||
function agentRunErrorStatus(code: string): number {
|
||||
if (code.includes('not_found')) return 404;
|
||||
if (code === 'budget_denied') return 402;
|
||||
if (code.includes('conflict') || code.includes('expired') || code.includes('consumed')) return 409;
|
||||
if (code.includes('invalid') || code === 'policy_blocked' || code === 'design_quote_blocked') {
|
||||
const normalizedCode = code.toLowerCase();
|
||||
const exactStatuses: Record<string, number> = {
|
||||
design_direction_not_found: 404,
|
||||
design_direction_unavailable: 409,
|
||||
design_revision_conflict: 409,
|
||||
design_idempotency_conflict: 409,
|
||||
design_prompt_unavailable: 409,
|
||||
design_reasoner_unavailable: 503,
|
||||
design_reasoner_invalid: 502,
|
||||
design_field_locked: 409,
|
||||
design_generation_unavailable: 503,
|
||||
design_quote_expired: 409,
|
||||
design_quote_consumed: 409,
|
||||
design_quote_invalid: 409,
|
||||
design_quote_dependency_invalid: 409,
|
||||
budget_denied: 402,
|
||||
design_billing_unavailable: 503,
|
||||
design_state_unavailable: 409,
|
||||
design_command_invalid: 400,
|
||||
design_input_invalid: 422,
|
||||
design_agent_run_failed: 502,
|
||||
design_agent_run_cancelled: 409,
|
||||
};
|
||||
if (exactStatuses[normalizedCode] !== undefined) return exactStatuses[normalizedCode];
|
||||
if (normalizedCode.includes('not_found')) return 404;
|
||||
if (normalizedCode.includes('conflict')
|
||||
|| normalizedCode.includes('expired')
|
||||
|| normalizedCode.includes('consumed')) return 409;
|
||||
if (normalizedCode.includes('invalid')
|
||||
|| normalizedCode === 'policy_blocked'
|
||||
|| normalizedCode === 'design_quote_blocked') {
|
||||
return 422;
|
||||
}
|
||||
if (code.includes('unavailable')) return 503;
|
||||
if (normalizedCode.includes('unavailable')) return 503;
|
||||
return 502;
|
||||
}
|
||||
|
||||
function commandFailureError(
|
||||
error: unknown,
|
||||
outcome: DesignCommandFailureOutcome,
|
||||
): DesignWorkspaceModuleError {
|
||||
if (error instanceof DesignWorkspaceModuleError) {
|
||||
return new DesignWorkspaceModuleError(
|
||||
error.status,
|
||||
error.code,
|
||||
userFacingErrorMessage(error.code),
|
||||
outcome,
|
||||
);
|
||||
}
|
||||
return new DesignWorkspaceModuleError(
|
||||
502,
|
||||
'DESIGN_WORKSPACE_REQUEST_FAILED',
|
||||
'AI 设计服务暂时无法连接',
|
||||
outcome,
|
||||
);
|
||||
}
|
||||
|
||||
function submissionFailureOutcome(error: unknown): DesignCommandFailureOutcome {
|
||||
if (error instanceof DesignWorkspaceModuleError
|
||||
&& error.status >= 400
|
||||
&& error.status < 500
|
||||
&& error.status !== 408) {
|
||||
return 'definitive_failure';
|
||||
}
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
function designRequestTimeoutError(): DesignWorkspaceModuleError {
|
||||
return new DesignWorkspaceModuleError(
|
||||
504,
|
||||
@@ -716,11 +779,22 @@ export class WorksSquareDesignWorkspace implements DesignWorkspaceModule {
|
||||
}
|
||||
|
||||
async submitCommand(input: DesignCommandInput): Promise<DesignCommandResult> {
|
||||
const command = await this.requestJson<ServerAgentCommand>(
|
||||
`/api/agents/sessions/${encodeURIComponent(input.sessionId)}/commands`,
|
||||
{ method: 'POST', body: JSON.stringify(agentCommand(input)) },
|
||||
);
|
||||
const run = await this.waitForRun(input.sessionId, command.run_id);
|
||||
let command: ServerAgentCommand;
|
||||
try {
|
||||
command = await this.requestJson<ServerAgentCommand>(
|
||||
`/api/agents/sessions/${encodeURIComponent(input.sessionId)}/commands`,
|
||||
{ method: 'POST', body: JSON.stringify(agentCommand(input)) },
|
||||
);
|
||||
} catch (error) {
|
||||
throw commandFailureError(error, submissionFailureOutcome(error));
|
||||
}
|
||||
|
||||
let run: ServerAgentRun;
|
||||
try {
|
||||
run = await this.waitForRun(input.sessionId, command.run_id);
|
||||
} catch (error) {
|
||||
throw commandFailureError(error, 'unknown');
|
||||
}
|
||||
if (run.status !== 'succeeded') {
|
||||
const code = run.error?.code ?? (
|
||||
run.status === 'cancelled' ? 'design_agent_run_cancelled' : 'design_agent_run_failed'
|
||||
@@ -729,12 +803,19 @@ export class WorksSquareDesignWorkspace implements DesignWorkspaceModule {
|
||||
agentRunErrorStatus(code),
|
||||
code,
|
||||
userFacingErrorMessage(code),
|
||||
'definitive_failure',
|
||||
);
|
||||
}
|
||||
let workspace: DesignWorkspace;
|
||||
try {
|
||||
workspace = await this.getWorkspace(input.workspaceId);
|
||||
} catch (error) {
|
||||
throw commandFailureError(error, 'unknown');
|
||||
}
|
||||
return {
|
||||
clientOperationId: input.clientOperationId,
|
||||
runId: run.run_id,
|
||||
workspace: await this.getWorkspace(input.workspaceId),
|
||||
workspace,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user