fix: stabilize ai design history switching
This commit is contained in:
@@ -86,6 +86,7 @@ type ServerQuote = {
|
||||
};
|
||||
|
||||
type ServerMessage = {
|
||||
message_id?: string;
|
||||
role: DesignMessage['role'];
|
||||
kind: DesignMessage['kind'];
|
||||
text: string;
|
||||
@@ -119,6 +120,10 @@ type ServerConversationSummary = {
|
||||
|
||||
type ServerConversation = ServerConversationSummary & {
|
||||
messages: ServerMessage[];
|
||||
message_page?: {
|
||||
has_older: boolean;
|
||||
next_before: string | null;
|
||||
};
|
||||
};
|
||||
|
||||
type ServerWorkspace = ServerWorkspaceSummary & {
|
||||
@@ -264,6 +269,7 @@ type AgentCommandChannel = {
|
||||
};
|
||||
|
||||
const AGENT_WEBSOCKET_OPEN = 1;
|
||||
const AGENT_WEBSOCKET_OPEN_TIMEOUT_MS = 10_000;
|
||||
const AGENT_WEBSOCKET_PING_INTERVAL_MS = 20_000;
|
||||
const AGENT_COMMAND_ACK_TIMEOUT_MS = 5_000;
|
||||
const AGENT_RUN_INITIAL_POLL_INTERVAL_MS = 1_000;
|
||||
@@ -393,7 +399,8 @@ function mapConversationSummary(
|
||||
|
||||
function mapConversation(conversation: ServerConversation): DesignConversation {
|
||||
const messages = conversation.messages.map((message, index) => ({
|
||||
id: `${conversation.conversation_id}:${message.turn_revision}:${message.role}:${index}`,
|
||||
id: message.message_id
|
||||
?? `${conversation.conversation_id}:${message.turn_revision}:${message.role}:${index}`,
|
||||
role: message.role,
|
||||
kind: message.kind,
|
||||
text: message.text,
|
||||
@@ -408,6 +415,12 @@ function mapConversation(conversation: ServerConversation): DesignConversation {
|
||||
?? normalizeMessagePreview(conversation.latest_message_preview)
|
||||
?? normalizeMessagePreview(conversation.brief.summary),
|
||||
messages,
|
||||
messagePage: conversation.message_page
|
||||
? {
|
||||
hasOlder: conversation.message_page.has_older,
|
||||
nextBefore: conversation.message_page.next_before,
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -935,9 +948,11 @@ export class WorksSquareDesignWorkspace implements DesignWorkspaceModule {
|
||||
async getConversation(
|
||||
workspaceId: string,
|
||||
conversationId: string,
|
||||
before?: string,
|
||||
): Promise<DesignConversation> {
|
||||
const query = before ? `?before=${encodeURIComponent(before)}` : '';
|
||||
const conversation = await this.requestJson<ServerConversation>(
|
||||
`/api/design/workspaces/${encodeURIComponent(workspaceId)}/conversations/${encodeURIComponent(conversationId)}`,
|
||||
`/api/design/workspaces/${encodeURIComponent(workspaceId)}/conversations/${encodeURIComponent(conversationId)}${query}`,
|
||||
);
|
||||
this.rememberConversation(conversation);
|
||||
return mapConversation(conversation);
|
||||
@@ -1328,6 +1343,7 @@ export class WorksSquareDesignWorkspace implements DesignWorkspaceModule {
|
||||
let ending = false;
|
||||
let settled = false;
|
||||
let heartbeat: ReturnType<typeof setInterval> | null = null;
|
||||
let openedTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||
let unregister = () => undefined;
|
||||
let resolveOpened: () => void = () => undefined;
|
||||
let rejectOpened: (error: unknown) => void = () => undefined;
|
||||
@@ -1349,6 +1365,8 @@ export class WorksSquareDesignWorkspace implements DesignWorkspaceModule {
|
||||
socket.onclose = null;
|
||||
if (heartbeat !== null) clearInterval(heartbeat);
|
||||
heartbeat = null;
|
||||
if (openedTimeout !== null) clearTimeout(openedTimeout);
|
||||
openedTimeout = null;
|
||||
unregister();
|
||||
if (didOpen) {
|
||||
this.unregisterAgentCommandChannel(sessionId, commandChannel);
|
||||
@@ -1450,6 +1468,19 @@ export class WorksSquareDesignWorkspace implements DesignWorkspaceModule {
|
||||
input.conversationId,
|
||||
close,
|
||||
);
|
||||
openedTimeout = setTimeout(() => {
|
||||
if (ending || didOpen) return;
|
||||
beginEnd(new DesignWorkspaceModuleError(
|
||||
504,
|
||||
'DESIGN_EVENT_STREAM_TIMEOUT',
|
||||
'AI 设计任务状态连接超时,请稍后重试',
|
||||
));
|
||||
try {
|
||||
socket.close(1000, 'Timed out opening design event stream');
|
||||
} catch {
|
||||
// settle below remains authoritative when the transport cannot close.
|
||||
}
|
||||
}, AGENT_WEBSOCKET_OPEN_TIMEOUT_MS);
|
||||
await opened;
|
||||
return {
|
||||
events: queue.events,
|
||||
|
||||
Reference in New Issue
Block a user