Skip to content

pref(provider): Config/Provider 代码质量修复 — 冗余清理与结构重构#150

Merged
minorcell merged 1 commit into
1024XEngineer:mainfrom
phantom5099:main
Apr 4, 2026
Merged

pref(provider): Config/Provider 代码质量修复 — 冗余清理与结构重构#150
minorcell merged 1 commit into
1024XEngineer:mainfrom
phantom5099:main

Conversation

@phantom5099

Copy link
Copy Markdown
Collaborator

变更说明

本 PR 对 internal/configinternal/provider 包执行了代码质量修复,涵盖错误定义去重、死代码清除、OpenAI 流式解析函数结构重构、网络错误检测加固四个方面。

主要改动

1. 消除跨包错误重复(config 层)

文件: internal/config/selection.go

  • 删除 ErrDriverNotFound 错误变量(与 provider.ErrDriverNotFound 语义重叠)
  • 新增 ErrDriverUnsupported = errors.New("provider driver not supported by current runtime")
  • 更新 SelectProvider() 和其内部 Update 回调中的错误返回,从泛化的「未找到」改为语义精确的「驱动不被支持」

文件: internal/config/selection_test.go

  • TestSelectionServiceSelectProviderRejectsUnsupportedDriver 断言更新:ErrDriverNotFoundErrDriverUnsupported

设计理由: config 包不应持有 provider 领域的错误定义。当驱动类型不在注册表中时,应表达的是「当前运行时环境不支持该驱动」而非「找不到驱动」。


2. 清除死代码(config 层)

文件: internal/config/model.go

  • 删除 函数 ContainsModelID(models []string, model string) bool
  • 全局搜索确认零调用方,属于历史残留

注: 当前模型 ID 匹配已由 containsModelDescriptorID() (selection.go) 承担,基于 ModelDescriptor 结构体而非裸字符串,是更完整的实现。


3. OpenAI consumeStream 结构重构(provider/openai 层)

文件: internal/provider/openai/openai.go

这是本次改动量最大的部分。原始 consumeStream 是一个约 120 行的单体函数,包含嵌套闭包和深层 if 分支。重构后提取为以下独立函数:

新函数 职责 原始位置
processChunk (闭包) 解析单个 SSE data payload,分发到内容累积 / tool call 合并 / usage 提取 内联在主循环中
finishStream (闭包) 统一退出路径:发送 message_done 事件 + 组装 ChatResponse 原有两条重复路径合并
extractStreamUsage(usage, raw) 从 OpenAI usage DTO 覆盖累积 token 统计 内联在 processChunk 中
mergeToolCallDelta(ctx, events, toolCalls, delta) 累积 tool call delta,按需发出 start/delta 事件 内联 4 层嵌套
flushDataLines(dataLines, reset, processChunk) 缓冲 data lines 合并 + 委托处理 原 flushEvent 闭包
finalizeResponse(content, toolCalls, finishReason, usage) 将所有累积状态组装为最终响应 内联在退出路径中

关键改进:

  • DRY: 两条完全相同的退出路径 → 一个 finishStream 闭包
  • 嵌套降低: tool call delta 处理从 4 层 if 嵌套降到 2 层
  • 可测试性: mergeToolCallDeltaflushDataLinesfinalizeResponseextractStreamUsage 均为独立函数,可单独编写单元测试

附带 bug 修正: chunkDelta.ToolCalls JSON tag 从错误的 "tools" 修正为协议要求的 "tool_calls"。此 tag 错误会导致 SSE 流中 tool call delta 反序列化失败,tool call 功能完全不可用。


4. isNetworkError 双策略重写(transport 层)

文件: internal/provider/transport/retry.go

// 重写前: 纯字符串匹配(脆弱)
func isNetworkError(err error) bool {
    msg := err.Error()
    return strings.Contains(msg, "connection refused") || ...
}

// 重写后: 类型断言优先 + 消息兜底
func isNetworkError(err error) bool {
    // Strategy 1: 类型断言(可靠)
    var opErr *net.OpError
    if errors.As(err, &opErr) { return true }
    if errors.Is(err, context.DeadlineExceeded) { return true }
    // Strategy 2: 消息匹配 fallback(兼容包装错误)
    msg := err.Error()
    for _, indicator := range [...] {
        "connection refused", "connection reset",
        "connection timed out", "no such host",
        "dial tcp", "timeout",
    } { if strings.Contains(msg, indicator) { return true } }
    return false
}

设计理由: Go 标准库网络操作返回的底层错误通常是 *net.OpError,通过 errors.As 做类型断言是最可靠的检测方式。消息匹配作为 fallback 兼容被 fmt.Errorf 包装过的错误场景。


变更清单

文件 操作 行数变化(估算)
internal/config/selection.go 修改 ~5 行替换
internal/config/model.go 删除 -8 行(删除死代码)
internal/config/selection_test.go 修改 ~2 行断言更新
internal/provider/openai/openai.go 重构 净增约 40 行(提取独立函数),但单函数复杂度大幅下降
internal/provider/transport/retry.go 修改 约 20 行重写

测试验证

  • go build ./... 编译通过
  • go test ./internal/config/ ./internal/provider/ ./internal/tui/ -count=1 全部通过
  • TestProviderChatConsumesSSE — tool call 事件序列正确(start → delta → message_done)
  • TestSelectionServiceSelectProviderRejectsUnsupportedDriverErrDriverUnsupported 断言正确
  • retry 相关测试 — isNetworkError 双策略覆盖网络超时场景

预期收益

  1. 可维护性提升: consumeStream 从单体函数拆分为职责明确的子函数,后续修改 tool call 或 usage 解析逻辑时不再需要在 120 行函数中定位目标代码段
  2. bug 修复: chunkDelta.ToolCalls JSON tag 修正确保 tool call streaming 功能正常工作
  3. 可靠性提升: isNetworkError 类型断言优先策略减少漏判,重试中间件在网络抖动场景下表现更稳定
  4. 代码整洁度: 消除死代码和跨包重复定义,减少认知负担
  5. 未来可测试性: 提取出的纯函数(mergeToolCallDeltafinalizeResponse 等)可独立编写单元测试,无需构造完整的 SSE 流模拟

风险与回退

  • 低风险: 所有改动均为内部实现重构,对外接口(Provider.ChatRetryTransport.RoundTripSelectionService.SelectProvider)签名不变
  • 错误值变更: 上层若用 errors.Is(err, config.ErrDriverNotFound) 做精确匹配需同步改为 ErrDriverUnsupported——经搜索确认仅影响测试文件
  • 回退方案: 单个 commit 可整体 revert,无数据库迁移或配置格式变更

@codecov

codecov Bot commented Apr 4, 2026

Copy link
Copy Markdown

@minorcell minorcell merged commit dc772c7 into 1024XEngineer:main Apr 4, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants