From db3c63ffe444be633091ef7618b672cd501d4b51 Mon Sep 17 00:00:00 2001 From: hex2077 Date: Mon, 20 Oct 2025 21:16:06 +0800 Subject: [PATCH] =?UTF-8?q?refactor(stream):=20=E9=87=8D=E6=9E=84=E6=B5=81?= =?UTF-8?q?=E5=BC=8F=E5=93=8D=E5=BA=94=E5=A4=84=E7=90=86=E5=99=A8=E4=B8=8E?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E6=B1=A0=E8=B0=83=E5=BA=A6=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 针对 claude-kiro 模块的事件流解析器进行架构升级,引入双模式 正则匹配策略实现向后兼容。provider-pool-manager 模块通过引入 延迟写入队列机制重构持久化层,消除冗余的迭代逻辑。 核心变更: - 实现 SSE 标准格式与遗留格式的自适应解析器 - 重构 JSON 边界检测算法,增强空白字符处理 - 引入基于 Set 的批量写入队列替代即时持久化 - 移除供应商选择中的多余循环,采用直接索引计算 - 调整异常传播策略,将错误向上层抛出而非内部消化 技术细节:通过定时器合并多次保存请求,将 I/O 操作从 O(n) 降低到 O(1);时间戳标准化逻辑由多分支条件简化为三元表达式; 转义字符处理采用负向后查找断言避免误替换。 --- src/claude/claude-kiro.js | 44 +++++++++++---- src/provider-pool-manager.js | 100 +++++++++++++++++++++++------------ 2 files changed, 102 insertions(+), 42 deletions(-) diff --git a/src/claude/claude-kiro.js b/src/claude/claude-kiro.js index 585a1b5..719fa5c 100644 --- a/src/claude/claude-kiro.js +++ b/src/claude/claude-kiro.js @@ -669,14 +669,31 @@ async initializeAuth(forceRefresh = false) { let fullContent = ''; const toolCalls = []; let currentToolCallDict = null; + // console.log(`rawStr=${rawStr}`); - const eventBlockRegex = /event({.*?(?=event{|$))/gs; + // 改进的 SSE 事件解析:匹配 :message-typeevent 后面的 JSON 数据 + // 使用更精确的正则来匹配 SSE 格式的事件 + const sseEventRegex = /:message-typeevent(\{[^]*?(?=:event-type|$))/g; + const legacyEventRegex = /event(\{.*?(?=event\{|$))/gs; + + // 首先尝试使用 SSE 格式解析 + let matches = [...rawStr.matchAll(sseEventRegex)]; + + // 如果 SSE 格式没有匹配到,回退到旧的格式 + if (matches.length === 0) { + matches = [...rawStr.matchAll(legacyEventRegex)]; + } - for (const match of rawStr.matchAll(eventBlockRegex)) { + for (const match of matches) { const potentialJsonBlock = match[1]; + if (!potentialJsonBlock || potentialJsonBlock.trim().length === 0) { + continue; + } + + // 尝试找到完整的 JSON 对象 let searchPos = 0; while ((searchPos = potentialJsonBlock.indexOf('}', searchPos + 1)) !== -1) { - const jsonCandidate = potentialJsonBlock.substring(0, searchPos + 1); + const jsonCandidate = potentialJsonBlock.substring(0, searchPos + 1).trim(); try { const eventData = JSON.parse(jsonCandidate); @@ -700,22 +717,30 @@ async initializeAuth(forceRefresh = false) { const args = JSON.parse(currentToolCallDict.function.arguments); currentToolCallDict.function.arguments = JSON.stringify(args); } catch (e) { - console.warn(`Tool call arguments not valid JSON: ${currentToolCallDict.function.arguments}`); + console.warn(`[Kiro] Tool call arguments not valid JSON: ${currentToolCallDict.function.arguments}`); } toolCalls.push(currentToolCallDict); currentToolCallDict = null; } } else if (!eventData.followupPrompt && eventData.content) { - const decodedContent = eventData.content.replace(/\\n/g, '\n'); + // 处理内容,移除转义字符 + let decodedContent = eventData.content; + // 处理常见的转义序列 + decodedContent = decodedContent.replace(/(? { + this._flushPendingSaves(); + }, this.saveDebounceTime); + } + + /** + * 优化1: 批量保存所有待保存的 providerType + * @private + */ + async _flushPendingSaves() { + const typesToSave = Array.from(this.pendingSaves); + this.pendingSaves.clear(); + this.saveTimer = null; + + for (const providerType of typesToSave) { + await this._saveProviderPoolsToJson(providerType); + } + } + /** * Saves the current provider pools configuration to the JSON file. * @private