fix(design): preserve command outcome certainty

This commit is contained in:
2026-09-03 18:25:06 +08:00
parent 4d8b19eeb5
commit a16dfd0d6f
15 changed files with 576 additions and 23 deletions

View File

@@ -137,9 +137,11 @@ function isUnavailableError(error: unknown): boolean {
function isDirectionConflict(error: unknown): boolean {
return error instanceof ImageWorkspaceApiError
&& (error.status === 409
|| error.code === 'DESIGN_DIRECTION_REVISION_CONFLICT'
|| error.code === 'DIRECTION_REVISION_CONFLICT');
&& [
'design_revision_conflict',
'design_direction_revision_conflict',
'direction_revision_conflict',
].includes(error.code.toLowerCase());
}
function isQuoteBlocked(error: unknown): boolean {
@@ -147,6 +149,15 @@ function isQuoteBlocked(error: unknown): boolean {
&& error.code.toLowerCase() === 'design_quote_blocked';
}
function isDefinitiveCommandFailure(error: unknown): error is ImageWorkspaceApiError {
return error instanceof ImageWorkspaceApiError
&& error.commandOutcome === 'definitive_failure';
}
function isUnknownCommandOutcome(error: unknown): boolean {
return error instanceof ImageWorkspaceApiError && error.commandOutcome === 'unknown';
}
function parseWorkspaceEvent(event: Event): DesignWorkspaceEvent | null {
const data = (event as MessageEvent<unknown>).data;
if (typeof data !== 'string') return null;
@@ -299,7 +310,16 @@ export const useImageWorkspaceStore = create<ImageWorkspaceState>((set, get) =>
return result.workspace;
} catch (error) {
const message = messageForError(error);
if (isDirectionConflict(error)) {
if (isUnknownCommandOutcome(error)) {
set((state) => ({
pendingOperations: {
...state.pendingOperations,
[operation.id]: { ...operation, status: 'unknown', error: message },
},
...(isAuthError(error) ? { status: 'auth-required' as const } : {}),
error: '操作结果尚未确认,可使用同一操作标识安全重试',
}));
} else if (isDirectionConflict(error)) {
set((state) => {
const pendingOperations = { ...state.pendingOperations };
delete pendingOperations[operation.id];
@@ -318,6 +338,15 @@ export const useImageWorkspaceStore = create<ImageWorkspaceState>((set, get) =>
delete pendingOperations[operation.id];
return { pendingOperations, error: null };
});
} else if (isDefinitiveCommandFailure(error)) {
set((state) => {
const pendingOperations = { ...state.pendingOperations };
delete pendingOperations[operation.id];
const assistantStreams = { ...state.assistantStreams };
delete assistantStreams[operation.id];
return { pendingOperations, assistantStreams, error: message };
});
if (error.status === 409) await get().refreshWorkspace().catch(() => null);
} else {
set((state) => ({
pendingOperations: {