保证 request_id 会话固定
This commit is contained in:
parent
eae12d45ad
commit
ebc8c52368
@ -370,6 +370,9 @@ function checkAndFixLoadingState() {
|
|||||||
if (shouldBeLoading !== chatState.loading) {
|
if (shouldBeLoading !== chatState.loading) {
|
||||||
log(`[checkAndFixLoadingState] 状态不一致,修复 - 应该loading=${shouldBeLoading}, 当前=${chatState.loading}`);
|
log(`[checkAndFixLoadingState] 状态不一致,修复 - 应该loading=${shouldBeLoading}, 当前=${chatState.loading}`);
|
||||||
chatStore.setLoading(shouldBeLoading);
|
chatStore.setLoading(shouldBeLoading);
|
||||||
|
|
||||||
|
// 强制更新senderKey,确保a-x-sender组件重新渲染
|
||||||
|
chatState.senderKey = Date.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新本地状态,只在需要时更新
|
// 更新本地状态,只在需要时更新
|
||||||
@ -381,8 +384,8 @@ function checkAndFixLoadingState() {
|
|||||||
lastLoadingState.value = shouldBeLoading;
|
lastLoadingState.value = shouldBeLoading;
|
||||||
lastPendingState.value = hasPendingMessage;
|
lastPendingState.value = hasPendingMessage;
|
||||||
|
|
||||||
// 仅在需要时更新senderKey
|
// 仅在需要时更新senderKey (此条件可能不再需要,但保留为了防止其他情况)
|
||||||
if (shouldBeLoading !== actualLoadingState.value || Date.now() - chatState.senderKey > 5000) {
|
if (shouldBeLoading !== actualLoadingState.value) {
|
||||||
chatState.senderKey = Date.now();
|
chatState.senderKey = Date.now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,18 +41,24 @@ try {
|
|||||||
|
|
||||||
// 添加常量定义
|
// 添加常量定义
|
||||||
const REQUEST_TIMEOUT = 5000; // 请求超时时间(毫秒)
|
const REQUEST_TIMEOUT = 5000; // 请求超时时间(毫秒)
|
||||||
|
const LOCAL_STORAGE_REQUEST_ID_KEY = 'vscode_ai_chat_request_id'; // 保存requestId的localStorage键名
|
||||||
|
|
||||||
// WebSocket服务- 浏览器环境下实现
|
// WebSocket服务- 浏览器环境下实现
|
||||||
export class WebSocketService {
|
export class WebSocketService {
|
||||||
private socket: WebSocket | null = null;
|
private socket: WebSocket | null = null;
|
||||||
private backoffTime = 1000;
|
private backoffTime = 1000;
|
||||||
private nextRequestId = 1;
|
// 使用静态变量确保在同一个会话中所有的WebSocketService实例共享同一个requestId序列
|
||||||
|
private static _nextRequestId = 1;
|
||||||
private requestHandlers: Map<number, (response: any) => void> = new Map();
|
private requestHandlers: Map<number, (response: any) => void> = new Map();
|
||||||
private reconnectAttempts = 0;
|
private reconnectAttempts = 0;
|
||||||
private reconnectTimer: NodeJS.Timeout | null = null;
|
private reconnectTimer: NodeJS.Timeout | null = null;
|
||||||
private readonly MAX_RECONNECT_ATTEMPTS = 5;
|
private readonly MAX_RECONNECT_ATTEMPTS = 5;
|
||||||
private readonly RECONNECT_DELAY = 2000;
|
private readonly RECONNECT_DELAY = 2000;
|
||||||
private isReconnecting = false;
|
private isReconnecting = false;
|
||||||
|
private _hasLoggedRequestId = false; // 用于跟踪是否已记录过requestId
|
||||||
|
|
||||||
|
// 内存存储,用于在localStorage不可用时的备用
|
||||||
|
private static memoryStorage: Record<string, string> = {};
|
||||||
|
|
||||||
public isConnected = false;
|
public isConnected = false;
|
||||||
public isLoading = false;
|
public isLoading = false;
|
||||||
@ -62,7 +68,77 @@ export class WebSocketService {
|
|||||||
public messages: ChatMessage[] = []; // 聊天消息历史
|
public messages: ChatMessage[] = []; // 聊天消息历史
|
||||||
private eventListeners: Map<string, Array<(data?: any) => void>> = new Map();
|
private eventListeners: Map<string, Array<(data?: any) => void>> = new Map();
|
||||||
|
|
||||||
constructor(private apiUrl: string, private apiKey: string, private logger: (message: string) => void = console.log) {}
|
/**
|
||||||
|
* 安全地获取存储值,优先使用localStorage,失败时使用内存存储
|
||||||
|
* @param key 存储键
|
||||||
|
* @returns 存储的值或null
|
||||||
|
*/
|
||||||
|
private safeGetItem(key: string): string | null {
|
||||||
|
try {
|
||||||
|
// 首先尝试从localStorage获取
|
||||||
|
if (typeof localStorage !== 'undefined') {
|
||||||
|
return localStorage.getItem(key);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.logger(`无法从localStorage读取数据: ${error}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回退到内存存储
|
||||||
|
return WebSocketService.memoryStorage[key] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全地设置存储值,优先使用localStorage,失败时使用内存存储
|
||||||
|
* @param key 存储键
|
||||||
|
* @param value 要存储的值
|
||||||
|
*/
|
||||||
|
private safeSetItem(key: string, value: string): void {
|
||||||
|
try {
|
||||||
|
// 首先尝试存储到localStorage
|
||||||
|
if (typeof localStorage !== 'undefined') {
|
||||||
|
localStorage.setItem(key, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.logger(`无法写入数据到localStorage: ${error}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回退到内存存储
|
||||||
|
WebSocketService.memoryStorage[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private apiUrl: string, private apiKey: string, private logger: (message: string) => void = console.log) {
|
||||||
|
// 仅在类的静态变量_nextRequestId还是初始值时才从存储中恢复
|
||||||
|
if (WebSocketService._nextRequestId === 1) {
|
||||||
|
// 从存储中恢复requestId,确保在同一VSCode会话中保持一致
|
||||||
|
const savedRequestId = this.safeGetItem(LOCAL_STORAGE_REQUEST_ID_KEY);
|
||||||
|
|
||||||
|
if (savedRequestId) {
|
||||||
|
const parsedId = parseInt(savedRequestId, 10);
|
||||||
|
if (!isNaN(parsedId) && parsedId > 0) {
|
||||||
|
WebSocketService._nextRequestId = parsedId;
|
||||||
|
this.logger(`从存储中恢复requestId: ${WebSocketService._nextRequestId}`);
|
||||||
|
} else {
|
||||||
|
// 如果存储的值无效,生成一个新的随机ID并保存
|
||||||
|
// 使用时间戳作为基础,确保唯一性
|
||||||
|
const timestamp = Date.now();
|
||||||
|
WebSocketService._nextRequestId = timestamp % 100000000 + Math.floor(Math.random() * 10000);
|
||||||
|
this.safeSetItem(LOCAL_STORAGE_REQUEST_ID_KEY, WebSocketService._nextRequestId.toString());
|
||||||
|
this.logger(`创建新的随机requestId: ${WebSocketService._nextRequestId} (基于时间戳)`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 首次运行,创建新的随机ID
|
||||||
|
// 使用时间戳作为基础,确保唯一性
|
||||||
|
const timestamp = Date.now();
|
||||||
|
WebSocketService._nextRequestId = timestamp % 100000000 + Math.floor(Math.random() * 10000);
|
||||||
|
this.safeSetItem(LOCAL_STORAGE_REQUEST_ID_KEY, WebSocketService._nextRequestId.toString());
|
||||||
|
this.logger(`创建新的随机requestId: ${WebSocketService._nextRequestId} (基于时间戳)`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 静态变量已初始化,记录当前值
|
||||||
|
this.logger(`使用已初始化的会话requestId: ${WebSocketService._nextRequestId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 连接到WebSocket服务
|
* 连接到WebSocket服务
|
||||||
@ -500,10 +576,17 @@ export class WebSocketService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成唯一的请求ID
|
* 生成唯一的请求ID - 在同一会话内保持不变,确保所有请求使用相同的ID
|
||||||
*/
|
*/
|
||||||
private generateRequestId(): number {
|
private generateRequestId(): number {
|
||||||
return this.nextRequestId++;
|
// 不再自增,每次返回相同的请求ID
|
||||||
|
// 仅在初始请求时记录日志,避免日志过多
|
||||||
|
if (!this._hasLoggedRequestId) {
|
||||||
|
this.logger(`使用固定请求ID: ${WebSocketService._nextRequestId} (会话中保持一致)`);
|
||||||
|
this._hasLoggedRequestId = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return WebSocketService._nextRequestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user