@@ -1,49 +1,49 @@
## 1. 基础类型层 — Canonical Model 和核心类型定义
- [ ] 1.1 创建 `internal/conversion/errors.go` :定义 ConversionError 结构体( Code, Message, ClientProtocol, ProviderProtocol, InterfaceType, Details, Cause) 和 ErrorCode 枚举( INVALID_INPUT, MISSING_REQUIRED_FIELD, INCOMPATIBLE_FEATURE, FIELD_MAPPING_FAILURE, TOOL_CALL_PARSE_ERROR, JSON_PARSE_ERROR, STREAM_STATE_ERROR, UTF8_DECODE_ERROR, PROTOCOL_CONSTRAINT_VIOLATION, ENCODING_FAILURE, INTERFACE_NOT_SUPPORTED) , 实现 error 接口
- [ ] 1.2 创建 `internal/conversion/interface.go` :定义 InterfaceType 枚举( CHAT, MODELS, MODEL_INFO, EMBEDDINGS, RERANK)
- [ ] 1.3 创建 `internal/conversion/provider.go` :定义 TargetProvider 结构体( BaseURL, APIKey, ModelName, AdapterConfig map[string]any) ; 编写测试
- [ ] 1.4 创建 `internal/conversion/canonical/types.go` :定义 CanonicalRequest( model, system, messages, tools, tool_choice, parameters, thinking, stream, user_id, output_format, parallel_tool_use) 、CanonicalMessage( role 枚举: system/user/assistant/tool, content []ContentBlock) 、ContentBlock( 使用 type 字段的 discriminated union: text/tool_use/tool_result/thinking, ToolInput 使用 json.RawMessage) 、CanonicalTool( name, description, input_schema) 、ToolChoice 联合体( auto/none/any/tool+name) 、RequestParameters( max_tokens, temperature, top_p, top_k, frequency_penalty, presence_penalty, stop_sequences) 、ThinkingConfig( type: enabled/disabled/adaptive, budget_tokens, effort) 、OutputFormat( json_object/json_schema+schema/text) 、CanonicalResponse( id, model, content, stop_reason 枚举, usage) 、CanonicalUsage( input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens, reasoning_tokens) 、SystemBlock( text) ; 编写构造和序列化测试
- [ ] 1.5 创建 `internal/conversion/canonical/stream.go` :定义 CanonicalStreamEvent 联合体( message_start, content_block_start, content_block_delta, content_block_stop, message_delta, message_stop, error, ping) 及各事件的具体结构( MessageStartEvent 含 message{id,model,usage}、ContentBlockStartEvent 含 index 和 content_block、ContentBlockDeltaEvent 含 index 和 delta、ContentBlockStopEvent 含 index、MessageDeltaEvent 含 delta{stop_reason} 和 usage、MessageStopEvent、ErrorEvent、PingEvent) , delta 联合体( text_delta, input_json_delta, thinking_delta) , content_block 联合体( text, tool_use, thinking) ; 编写测试
- [ ] 1.6 创建 `internal/conversion/canonical/extended.go` :定义扩展层 Canonical Models( CanonicalModelList, CanonicalModel, CanonicalModelInfo, CanonicalEmbeddingRequest, CanonicalEmbeddingResponse, CanonicalRerankRequest, CanonicalRerankResponse) ; 编写测试
- [x ] 1.1 创建 `internal/conversion/errors.go` :定义 ConversionError 结构体( Code, Message, ClientProtocol, ProviderProtocol, InterfaceType, Details, Cause) 和 ErrorCode 枚举( INVALID_INPUT, MISSING_REQUIRED_FIELD, INCOMPATIBLE_FEATURE, FIELD_MAPPING_FAILURE, TOOL_CALL_PARSE_ERROR, JSON_PARSE_ERROR, STREAM_STATE_ERROR, UTF8_DECODE_ERROR, PROTOCOL_CONSTRAINT_VIOLATION, ENCODING_FAILURE, INTERFACE_NOT_SUPPORTED) , 实现 error 接口
- [x ] 1.2 创建 `internal/conversion/interface.go` :定义 InterfaceType 枚举( CHAT, MODELS, MODEL_INFO, EMBEDDINGS, RERANK)
- [x ] 1.3 创建 `internal/conversion/provider.go` :定义 TargetProvider 结构体( BaseURL, APIKey, ModelName, AdapterConfig map[string]any) ; 编写测试
- [x ] 1.4 创建 `internal/conversion/canonical/types.go` :定义 CanonicalRequest( model, system, messages, tools, tool_choice, parameters, thinking, stream, user_id, output_format, parallel_tool_use) 、CanonicalMessage( role 枚举: system/user/assistant/tool, content []ContentBlock) 、ContentBlock( 使用 type 字段的 discriminated union: text/tool_use/tool_result/thinking, ToolInput 使用 json.RawMessage) 、CanonicalTool( name, description, input_schema) 、ToolChoice 联合体( auto/none/any/tool+name) 、RequestParameters( max_tokens, temperature, top_p, top_k, frequency_penalty, presence_penalty, stop_sequences) 、ThinkingConfig( type: enabled/disabled/adaptive, budget_tokens, effort) 、OutputFormat( json_object/json_schema+schema/text) 、CanonicalResponse( id, model, content, stop_reason 枚举, usage) 、CanonicalUsage( input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens, reasoning_tokens) 、SystemBlock( text) ; 编写构造和序列化测试
- [x ] 1.5 创建 `internal/conversion/canonical/stream.go` :定义 CanonicalStreamEvent 联合体( message_start, content_block_start, content_block_delta, content_block_stop, message_delta, message_stop, error, ping) 及各事件的具体结构( MessageStartEvent 含 message{id,model,usage}、ContentBlockStartEvent 含 index 和 content_block、ContentBlockDeltaEvent 含 index 和 delta、ContentBlockStopEvent 含 index、MessageDeltaEvent 含 delta{stop_reason} 和 usage、MessageStopEvent、ErrorEvent、PingEvent) , delta 联合体( text_delta, input_json_delta, thinking_delta) , content_block 联合体( text, tool_use, thinking) ; 编写测试
- [x ] 1.6 创建 `internal/conversion/canonical/extended.go` :定义扩展层 Canonical Models( CanonicalModelList, CanonicalModel, CanonicalModelInfo, CanonicalEmbeddingRequest, CanonicalEmbeddingResponse, CanonicalRerankRequest, CanonicalRerankResponse) ; 编写测试
## 2. 接口定义层 — Adapter、Stream、Middleware 接口
- [ ] 2.1 创建 `internal/conversion/adapter.go` :定义 ProtocolAdapter 接口( protocolName, protocolVersion, supportsPassthrough, detectInterfaceType, buildUrl, buildHeaders, supportsInterface, decodeRequest, encodeRequest, decodeResponse, encodeResponse, createStreamDecoder, createStreamEncoder, encodeError, 扩展层编解码方法: decodeModelsResponse/encodeModelsResponse/decodeModelInfoResponse/encodeModelInfoResponse/decodeEmbeddingRequest/encodeEmbeddingRequest/decodeEmbeddingResponse/encodeEmbeddingResponse/decodeRerankRequest/encodeRerankRequest/decodeRerankResponse/encodeRerankResponse) , 定义 AdapterRegistry 接口( register, get, listProtocols) 和 memoryRegistry 实现( sync.RWMutex 保护的 map) ; 编写 Registry 注册/查询/重复注册测试
- [ ] 2.2 创建 `internal/conversion/stream.go` :定义 StreamDecoder 接口( processChunk(rawChunk []byte) []CanonicalStreamEvent, flush() []CanonicalStreamEvent) 、StreamEncoder 接口( encodeEvent(event CanonicalStreamEvent) [][]byte, flush() [][]byte) 、StreamConverter 接口( processChunk(rawChunk []byte) [][]byte, flush() [][]byte) 、PassthroughStreamConverter 实现( 直接传递原始字节) 、CanonicalStreamConverter 实现(组合 StreamDecoder + MiddlewareChain + StreamEncoder, processChunk 内部调用 decoder → middleware → encoder 管道);编写 PassthroughStreamConverter 测试
- [ ] 2.3 创建 `internal/conversion/middleware.go` :定义 ConversionMiddleware 接口( intercept(canonical, clientProtocol, providerProtocol, context) (CanonicalRequest, error) 和可选的 interceptStreamEvent(event, clientProtocol, providerProtocol, context) (CanonicalStreamEvent, error)) 、ConversionContext 结构体( conversionId, interfaceType, timestamp, metadata) 、MiddlewareChain 结构体(按注册顺序链式执行,任一返回错误则中断后续);编写链式执行和中断测试
- [x ] 2.1 创建 `internal/conversion/adapter.go` :定义 ProtocolAdapter 接口( protocolName, protocolVersion, supportsPassthrough, detectInterfaceType, buildUrl, buildHeaders, supportsInterface, decodeRequest, encodeRequest, decodeResponse, encodeResponse, createStreamDecoder, createStreamEncoder, encodeError, 扩展层编解码方法: decodeModelsResponse/encodeModelsResponse/decodeModelInfoResponse/encodeModelInfoResponse/decodeEmbeddingRequest/encodeEmbeddingRequest/decodeEmbeddingResponse/encodeEmbeddingResponse/decodeRerankRequest/encodeRerankRequest/decodeRerankResponse/encodeRerankResponse) , 定义 AdapterRegistry 接口( register, get, listProtocols) 和 memoryRegistry 实现( sync.RWMutex 保护的 map) ; 编写 Registry 注册/查询/重复注册测试
- [x ] 2.2 创建 `internal/conversion/stream.go` :定义 StreamDecoder 接口( processChunk(rawChunk []byte) []CanonicalStreamEvent, flush() []CanonicalStreamEvent) 、StreamEncoder 接口( encodeEvent(event CanonicalStreamEvent) [][]byte, flush() [][]byte) 、StreamConverter 接口( processChunk(rawChunk []byte) [][]byte, flush() [][]byte) 、PassthroughStreamConverter 实现( 直接传递原始字节) 、CanonicalStreamConverter 实现(组合 StreamDecoder + MiddlewareChain + StreamEncoder, processChunk 内部调用 decoder → middleware → encoder 管道);编写 PassthroughStreamConverter 测试
- [x ] 2.3 创建 `internal/conversion/middleware.go` :定义 ConversionMiddleware 接口( intercept(canonical, clientProtocol, providerProtocol, context) (CanonicalRequest, error) 和可选的 interceptStreamEvent(event, clientProtocol, providerProtocol, context) (CanonicalStreamEvent, error)) 、ConversionContext 结构体( conversionId, interfaceType, timestamp, metadata) 、MiddlewareChain 结构体(按注册顺序链式执行,任一返回错误则中断后续);编写链式执行和中断测试
## 3. 引擎层 — ConversionEngine 门面
- [ ] 3.1 创建 `internal/conversion/engine.go` :定义 HTTPRequestSpec( URL, Method string, Headers map[string]string, Body []byte) 、HTTPResponseSpec( StatusCode int, Headers map[string]string, Body []byte) 、ConversionEngine struct( registry, middlewareChain) ; 实现 registerAdapter、use、isPassthrough、convertHttpRequest( 接口识别 → 透传判断 → clientAdapter.decode → middleware → providerAdapter.encode → providerAdapter.buildUrl + buildHeaders) 、convertHttpResponse( 透传判断 → providerAdapter.decodeResponse → clientAdapter.encodeResponse) 、createStreamConverter( 透传 → PassthroughStreamConverter, 否则 → CanonicalStreamConverter) 、内部 convertBody 分发( CHAT 走深度转换,扩展层走轻量映射,默认透传);编写集成测试:使用 mock adapter 测试跨协议转换、同协议透传、未知接口透传
- [x ] 3.1 创建 `internal/conversion/engine.go` :定义 HTTPRequestSpec( URL, Method string, Headers map[string]string, Body []byte) 、HTTPResponseSpec( StatusCode int, Headers map[string]string, Body []byte) 、ConversionEngine struct( registry, middlewareChain) ; 实现 registerAdapter、use、isPassthrough、convertHttpRequest( 接口识别 → 透传判断 → clientAdapter.decode → middleware → providerAdapter.encode → providerAdapter.buildUrl + buildHeaders) 、convertHttpResponse( 透传判断 → providerAdapter.decodeResponse → clientAdapter.encodeResponse) 、createStreamConverter( 透传 → PassthroughStreamConverter, 否则 → CanonicalStreamConverter) 、内部 convertBody 分发( CHAT 走深度转换,扩展层走轻量映射,默认透传);编写集成测试:使用 mock adapter 测试跨协议转换、同协议透传、未知接口透传
## 4. OpenAI Adapter 实现
- [ ] 4.1 创建 `internal/conversion/openai/types.go` : 从 旧 `internal/protocol/openai/types.go` 迁移 OpenAI 线路格式类型,补全缺失 字段( developer role, custom tools, reasoning_effort, reasoning_content, max_completion_tokens, parallel_tool_calls, response_format 的 json_schema 类型, stream_options, 废弃的 functions/function_call) ; 编写序列化测试
- [ ] 4.2 创建 `internal/conversion/openai/decoder.go` :实现 decodeRequest( 对照 conversion_openai.md §4.1: decodeSystemPrompt 提取 system+developer 消息、decodeMessage 含 tool_calls/refusal/reasoning_content 解码、tool 消息 tool_call_id→tool_use_id、decodeTools 含 function+custom 类型、decodeToolChoice 含 required→any/allowed_tools 降级、decodeParameters 含 max_completion_tokens 优先、decodeOutputFormat、decodeThinking 含 reasoning_effort→ThinkingConfig、废弃字段 functions→tools 兼容) 、decodeResponse( §5.2: content/refusal/reasoning_content/tool_calls 解码、finish_reason 映射表、usage 映射含 cached_tokens/reasoning_tokens) 、扩展层 decode( decodeModelsResponse、decodeEmbeddingRequest/Response、decodeRerankRequest/Response) ; 编写完整测试覆盖每类消息和字段映射
- [ ] 4.3 创建 `internal/conversion/openai/encoder.go` :实现 encodeRequest( 对照 conversion_openai.md §4.2: provider.model_name 覆盖、system 注入到 messages[0]、encodeMessage 含 tool_calls 编码到 message 顶层、角色交替合并、encodeTools 含 function 包装、encodeToolChoice 含 any→required、encodeParameters 含 max_completion_tokens、encodeOutputFormat、encodeThinking 含 disabled→"none") 、encodeResponse( §5.3: text→content、tool_use→tool_calls、thinking→reasoning_content、finish_reason 反向映射、usage 编码含 prompt_tokens_details) 、扩展层 encode( encodeModelsResponse、encodeEmbeddingRequest/Response、encodeRerankRequest/Response) ; 编写完整测试
- [ ] 4.4 创建 `internal/conversion/openai/adapter.go` :实现 OpenAI ProtocolAdapter( protocolName→"openai"、supportsPassthrough→true、detectInterfaceType 根据正则匹配识别 /v1/chat/completions→CHAT、/v1/models→MODELS 等、buildHeaders 含 Authorization+Content-Type+OpenAI-Organization、buildUrl 按接口类型映射、supportsInterface 对 CHAT/MODELS/MODEL_INFO/EMBEDDINGS/RERANK 返回 true、encodeError 含 ErrorCode→OpenAI 错误类型映射),组合 decoder 和 encoder 方法;编写测试覆盖所有路径模式和边界情况
- [ ] 4.5 创建 `internal/conversion/openai/stream_decoder.go` :实现 OpenAIStreamDecoder( 对照 conversion_openai.md §6.2-§6.3: processChunk 解析 SSE data 行,维护状态机 messageStarted/openBlocks/toolCallIdMap/toolCallNameMap/toolCallArguments/textBlockStarted/thinkingBlockStarted/utf8Remainder/accumulatedUsage, 首个 chunk→MessageStartEvent, delta.content→text block 生命周期, delta.tool_calls→tool_use block 生命周期含索引映射和参数累积, delta.reasoning_content→thinking block( 非标准) , delta.refusal→text block, finish_reason→关闭所有 open blocks + MessageDeltaEvent + MessageStopEvent, usage chunk→MessageDeltaEvent, [DONE]→flush 关闭);编写测试覆盖每种 delta 类型和边界情况(空 chunk、多 tool_calls、UTF-8 截断)
- [ ] 4.6 创建 `internal/conversion/openai/stream_encoder.go` :实现 OpenAIStreamEncoder( 对照 conversion_openai.md §6.4: encodeEvent, ContentBlockStart 缓冲策略等待首次 ContentBlockDelta 合并输出, tool_use id/name 在首次 delta 时合并编码, text_delta 直接输出 data: {choices:[{delta:{content}}]}, input_json_delta 含 tool_calls 数组编码, thinking_delta 含 reasoning_content 字段, MessageStartEvent→{choices:[{delta:{role:"assistant"}}]}, MessageDeltaEvent→{choices:[{delta:{},finish_reason}]}, MessageStopEvent→[DONE], PingEvent/ErrorEvent 丢弃, flush 输出缓冲区);编写测试
- [x ] 4.1 创建 `internal/conversion/openai/types.go` : 对照 `docs/conversion_openai.md` 全新定义 OpenAI 线路格式类型(不沿用 旧 `internal/protocol/openai/types.go` ),包含完整 字段( developer role, custom tools, reasoning_effort, reasoning_content, max_completion_tokens, parallel_tool_calls, response_format 的 json_schema 类型, stream_options, 废弃的 functions/function_call) ; 编写序列化测试
- [x ] 4.2 创建 `internal/conversion/openai/decoder.go` :实现 decodeRequest( 对照 conversion_openai.md §4.1: decodeSystemPrompt 提取 system+developer 消息、decodeMessage 含 tool_calls/refusal/reasoning_content 解码、tool 消息 tool_call_id→tool_use_id、decodeTools 含 function+custom 类型、decodeToolChoice 含 required→any/allowed_tools 降级、decodeParameters 含 max_completion_tokens 优先、decodeOutputFormat、decodeThinking 含 reasoning_effort→ThinkingConfig、废弃字段 functions→tools 兼容) 、decodeResponse( §5.2: content/refusal/reasoning_content/tool_calls 解码、finish_reason 映射表、usage 映射含 cached_tokens/reasoning_tokens) 、扩展层 decode( decodeModelsResponse、decodeEmbeddingRequest/Response、decodeRerankRequest/Response) ; 编写完整测试覆盖每类消息和字段映射
- [x ] 4.3 创建 `internal/conversion/openai/encoder.go` :实现 encodeRequest( 对照 conversion_openai.md §4.2: provider.model_name 覆盖、system 注入到 messages[0]、encodeMessage 含 tool_calls 编码到 message 顶层、角色交替合并、encodeTools 含 function 包装、encodeToolChoice 含 any→required、encodeParameters 含 max_completion_tokens、encodeOutputFormat、encodeThinking 含 disabled→"none") 、encodeResponse( §5.3: text→content、tool_use→tool_calls、thinking→reasoning_content、finish_reason 反向映射、usage 编码含 prompt_tokens_details) 、扩展层 encode( encodeModelsResponse、encodeEmbeddingRequest/Response、encodeRerankRequest/Response) ; 编写完整测试
- [x ] 4.4 创建 `internal/conversion/openai/adapter.go` :实现 OpenAI ProtocolAdapter( protocolName→"openai"、supportsPassthrough→true、detectInterfaceType 根据正则匹配识别 /v1/chat/completions→CHAT、/v1/models→MODELS 等、buildHeaders 含 Authorization+Content-Type+OpenAI-Organization、buildUrl 按接口类型映射、supportsInterface 对 CHAT/MODELS/MODEL_INFO/EMBEDDINGS/RERANK 返回 true、encodeError 含 ErrorCode→OpenAI 错误类型映射),组合 decoder 和 encoder 方法;编写测试覆盖所有路径模式和边界情况
- [x ] 4.5 创建 `internal/conversion/openai/stream_decoder.go` :实现 OpenAIStreamDecoder( 对照 conversion_openai.md §6.2-§6.3: processChunk 解析 SSE data 行,维护状态机 messageStarted/openBlocks/toolCallIdMap/toolCallNameMap/toolCallArguments/textBlockStarted/thinkingBlockStarted/utf8Remainder/accumulatedUsage, 首个 chunk→MessageStartEvent, delta.content→text block 生命周期, delta.tool_calls→tool_use block 生命周期含索引映射和参数累积, delta.reasoning_content→thinking block( 非标准) , delta.refusal→text block, finish_reason→关闭所有 open blocks + MessageDeltaEvent + MessageStopEvent, usage chunk→MessageDeltaEvent, [DONE]→flush 关闭);编写测试覆盖每种 delta 类型和边界情况(空 chunk、多 tool_calls、UTF-8 截断)
- [x ] 4.6 创建 `internal/conversion/openai/stream_encoder.go` :实现 OpenAIStreamEncoder( 对照 conversion_openai.md §6.4: encodeEvent, ContentBlockStart 缓冲策略等待首次 ContentBlockDelta 合并输出, tool_use id/name 在首次 delta 时合并编码, text_delta 直接输出 data: {choices:[{delta:{content}}]}, input_json_delta 含 tool_calls 数组编码, thinking_delta 含 reasoning_content 字段, MessageStartEvent→{choices:[{delta:{role:"assistant"}}]}, MessageDeltaEvent→{choices:[{delta:{},finish_reason}]}, MessageStopEvent→[DONE], PingEvent/ErrorEvent 丢弃, flush 输出缓冲区);编写测试
## 5. Anthropic Adapter 实现(与 Layer 4 并行)
- [ ] 5.1 创建 `internal/conversion/anthropic/types.go` : 从 旧 `internal/protocol/anthropic/types.go` 迁移 Anthropic 线路格式类型,补全缺失 字段( thinking.type 含 adaptive、output_config.format/effort、disable_parallel_tool_use、metadata.user_id、redacted_thinking、pause_turn/refusal stop_reason、stop_details、container、cache_control) ; 编写序列化测试
- [ ] 5.2 创建 `internal/conversion/anthropic/decoder.go` :实现 decodeRequest( 对照 conversion_anthropic.md §4.1: decodeSystem 从顶层 system 提取、decodeMessage 含 tool_result 从 user 消息拆分为独立 tool 角色消息、参数直接映射含 top_k、decodeThinking 含 enabled/disabled/adaptive 三种类型、decodeOutputFormat 仅支持 json_schema、公共字段提取含 metadata.user_id/disable_parallel_tool_use 反转/output_config.effort、协议特有字段 redacted_thinking 丢弃/cache_control 忽略) 、decodeResponse( §5.2: text/tool_use/thinking 块解码、redacted_thinking 丢弃、stop_reason 映射含 pause_turn/refusal、usage 映射含 cache_read_input_tokens/cache_creation_input_tokens) 、扩展层 decode( decodeModelsResponse 含 RFC3339→Unix 时间戳转换、decodeModelInfoResponse) ; 编写完整测试覆盖角色拆分、thinking 三种类型、时间戳转换
- [ ] 5.3 创建 `internal/conversion/anthropic/encoder.go` :实现 encodeRequest( 对照 conversion_anthropic.md §4.2: provider.model_name 覆盖、system 注入为顶层字段、encodeMessages 含 tool→user 合并(优先合并到相邻 user 消息)、首消息 user 保证(自动注入空 user) 、角色交替合并、encodeThinkingConfig 含 enabled/disabled/adaptive、encodeOutputFormat 含 json_object→空 schema 降级/text 丢弃、公共字段编码含 metadata.user_id/disable_parallel_tool_use 反转/output_config、参数编码含 max_tokens 必填/top_k 直接映射) 、encodeResponse( §5.3: text/tool_use/thinking 块直接编码、stop_reason 映射含 content_filter→end_turn 降级、usage 编码含 cache_read_input_tokens/cache_creation_input_tokens) 、扩展层 encode( encodeModelsResponse 含 Unix→RFC3339 转换和 has_more/first_id/last_id 字段、encodeModelInfoResponse) ; 编写完整测试覆盖角色合并、首消息注入、降级处理
- [ ] 5.4 创建 `internal/conversion/anthropic/adapter.go` :实现 Anthropic ProtocolAdapter( protocolName→"anthropic"、supportsPassthrough→true、detectInterfaceType 根据正则匹配识别 /v1/messages→CHAT、/v1/models→MODELS 等、buildHeaders 含 x-api-key + anthropic-version + anthropic-beta + Content-Type、buildUrl 按接口类型映射、supportsInterface 对 CHAT/MODELS/MODEL_INFO 返回 true 对 EMBEDDINGS/RERANK 返回 false、encodeError 返回 {type:"error",error:{type,message}});编写测试覆盖所有路径模式和边界情况
- [ ] 5.5 创建 `internal/conversion/anthropic/stream_decoder.go` :实现 AnthropicStreamDecoder( 对照 conversion_anthropic.md §6.2-§6.3:解析命名 SSE 事件 event: message_start/data: {...}, 1:1 映射到 CanonicalStreamEvent, 维护状态 messageStarted/redactedBlocks/utf8Remainder/accumulatedUsage, redacted_thinking 检测后加入 redactedBlocks 并丢弃后续 delta/stop, citations_delta/signature_delta 直接丢弃, server_tool_use 等服务端工具块丢弃, UTF-8 跨 chunk 安全处理);编写测试覆盖所有事件类型和 redacted_thinking 丢弃
- [ ] 5.6 创建 `internal/conversion/anthropic/stream_encoder.go` :实现 AnthropicStreamEncoder( 对照 conversion_anthropic.md §6.4:直接映射无缓冲,每个 CanonicalStreamEvent 直接编码为对应的 Anthropic 命名 SSE 事件,格式 event: `<type>` \ndata: `<json>` \n\n, delta 编码 text_delta/input_json_delta/thinking_delta 直接映射);编写测试
- [x ] 5.1 创建 `internal/conversion/anthropic/types.go` : 对照 `docs/conversion_anthropic.md` 全新定义 Anthropic 线路格式类型(不沿用 旧 `internal/protocol/anthropic/types.go` ),包含完整 字段( thinking.type 含 adaptive、output_config.format/effort、disable_parallel_tool_use、metadata.user_id、redacted_thinking、pause_turn/refusal stop_reason、stop_details、container、cache_control) ; 编写序列化测试
- [x ] 5.2 创建 `internal/conversion/anthropic/decoder.go` :实现 decodeRequest( 对照 conversion_anthropic.md §4.1: decodeSystem 从顶层 system 提取、decodeMessage 含 tool_result 从 user 消息拆分为独立 tool 角色消息、参数直接映射含 top_k、decodeThinking 含 enabled/disabled/adaptive 三种类型、decodeOutputFormat 仅支持 json_schema、公共字段提取含 metadata.user_id/disable_parallel_tool_use 反转/output_config.effort、协议特有字段 redacted_thinking 丢弃/cache_control 忽略) 、decodeResponse( §5.2: text/tool_use/thinking 块解码、redacted_thinking 丢弃、stop_reason 映射含 pause_turn/refusal、usage 映射含 cache_read_input_tokens/cache_creation_input_tokens) 、扩展层 decode( decodeModelsResponse 含 RFC3339→Unix 时间戳转换、decodeModelInfoResponse) ; 编写完整测试覆盖角色拆分、thinking 三种类型、时间戳转换
- [x ] 5.3 创建 `internal/conversion/anthropic/encoder.go` :实现 encodeRequest( 对照 conversion_anthropic.md §4.2: provider.model_name 覆盖、system 注入为顶层字段、encodeMessages 含 tool→user 合并(优先合并到相邻 user 消息)、首消息 user 保证(自动注入空 user) 、角色交替合并、encodeThinkingConfig 含 enabled/disabled/adaptive、encodeOutputFormat 含 json_object→空 schema 降级/text 丢弃、公共字段编码含 metadata.user_id/disable_parallel_tool_use 反转/output_config、参数编码含 max_tokens 必填/top_k 直接映射) 、encodeResponse( §5.3: text/tool_use/thinking 块直接编码、stop_reason 映射含 content_filter→end_turn 降级、usage 编码含 cache_read_input_tokens/cache_creation_input_tokens) 、扩展层 encode( encodeModelsResponse 含 Unix→RFC3339 转换和 has_more/first_id/last_id 字段、encodeModelInfoResponse) ; 编写完整测试覆盖角色合并、首消息注入、降级处理
- [x ] 5.4 创建 `internal/conversion/anthropic/adapter.go` :实现 Anthropic ProtocolAdapter( protocolName→"anthropic"、supportsPassthrough→true、detectInterfaceType 根据正则匹配识别 /v1/messages→CHAT、/v1/models→MODELS 等、buildHeaders 含 x-api-key + anthropic-version + anthropic-beta + Content-Type、buildUrl 按接口类型映射、supportsInterface 对 CHAT/MODELS/MODEL_INFO 返回 true 对 EMBEDDINGS/RERANK 返回 false、encodeError 返回 {type:"error",error:{type,message}});编写测试覆盖所有路径模式和边界情况
- [x ] 5.5 创建 `internal/conversion/anthropic/stream_decoder.go` :实现 AnthropicStreamDecoder( 对照 conversion_anthropic.md §6.2-§6.3:解析命名 SSE 事件 event: message_start/data: {...}, 1:1 映射到 CanonicalStreamEvent, 维护状态 messageStarted/redactedBlocks/utf8Remainder/accumulatedUsage, redacted_thinking 检测后加入 redactedBlocks 并丢弃后续 delta/stop, citations_delta/signature_delta 直接丢弃, server_tool_use 等服务端工具块丢弃, UTF-8 跨 chunk 安全处理);编写测试覆盖所有事件类型和 redacted_thinking 丢弃
- [x ] 5.6 创建 `internal/conversion/anthropic/stream_encoder.go` :实现 AnthropicStreamEncoder( 对照 conversion_anthropic.md §6.4:直接映射无缓冲,每个 CanonicalStreamEvent 直接编码为对应的 Anthropic 命名 SSE 事件,格式 event: `<type>` \ndata: `<json>` \n\n, delta 编码 text_delta/input_json_delta/thinking_delta 直接映射);编写测试
## 6. 基础设施改造 — Provider、Handler、Domain
- [ ] 6.1 修改 `internal/domain/provider.go` : Provider 结构体新增 Protocol string 字段;修改 `internal/config/models.go` : GORM Provider 模型同步新增 Protocol 字段( gorm:"column:protocol;default:'openai'");修改 `internal/repository/` 中 toDomainProvider 和 toConfigProvider 转换函数同步 Protocol 字段;修改 `internal/handler/provider_handler.go` : CreateProvider 和 UpdateProvider 的请求结构体新增 Protocol 字段(可选,默认 "openai"),创建/更新 Provider 时赋值 Protocol 字段, List/Get 响应中包含 Protocol 字段;更新 `internal/service/service_test.go` 中所有创建测试 Provider 的地方补充 Protocol 字段;更新 `internal/handler/handler_test.go` 中 Provider CRUD 测试的请求体补充 Protocol 字段;创建数据库迁移文件 `backend/migrations/YYYYMMDDHHMMSS_add_provider_protocol.sql` : ALTER TABLE providers ADD COLUMN protocol TEXT DEFAULT 'openai'
- [ ] 6.2 重写 `internal/provider/client.go` :定义 HTTPRequestSpec 和 HTTPResponseSpec( 或引用 conversion 包的定义),简化 ProviderClient 接口为 Send(ctx, HTTPRequestSpec) → (*HTTPResponseSpec, error) 和 SendStream(ctx, HTTPRequestSpec) → (<-chan StreamEvent, error),移除所有 openai.Adapter 硬编码依赖, Send 方法直接使用 http.NewRequest + spec.URL/Headers/Body, SendStream 保留现有 readStream goroutine 逻辑但输入改为 HTTPRequestSpec; 重写 `provider/client_test.go` :删除所有基于 openai.ChatCompletionRequest 的 旧测试用例,基于 HTTPRequestSpec 重写成功/失败/流式测试用例,使用 httptest.Server 验证请求构建和响应解析
- [ ] 6.3 创建 `internal/handler/proxy_handler.go` :实现 ProxyHandler struct( 依赖 ConversionEngine、ProviderClient、RoutingService、StatsService) , 实现 HandleProxy(w, r) 方法:从 URL 提取 clientProtocol( 仅支持 `/{protocol}/v1/...` 前缀路由,不支持旧路由)、解析请求体 JSON、调用 RoutingService.Route(modelName) 获取路由结果(含 Provider.Protocol 作为 providerProtocol) 、构建 TargetProvider、调用 engine.convertHttpRequest、调用 providerClient.Send/SendStream、调用 engine.convertHttpResponse、设置响应 Content-Type 和状态码、流式处理设置 text/event-stream 并用 StreamConverter 逐块转换写入、错误处理使用 clientAdapter.encodeError、异步调用 StatsService.Record; 编写测试使用 httptest + mock engine/client/service
- [ ] 6.4 修改 `cmd/server/main.go` :创建 AdapterRegistry 并注册 OpenAI 和 Anthropic Adapter、创建 ConversionEngine( 注入 registry) 、创建 ProxyHandler( 注入 engine + providerClient + routingService + statsService) 、配置 Gin 路由:新增 `/{protocol}/v1/{path:*}` → ProxyHandler.HandleProxy, 删除旧路由 `/v1/chat/completions` 和 `/v1/messages` ,移除旧的 OpenAIHandler 和 AnthropicHandler 的路由注册,移 除旧的 Adapter 创建代码
- [x ] 6.1 修改 `internal/domain/provider.go` : Provider 结构体新增 Protocol string 字段;修改 `internal/config/models.go` : GORM Provider 模型同步新增 Protocol 字段( gorm:"column:protocol;default:'openai'");修改 `internal/repository/` 中 toDomainProvider 和 toConfigProvider 转换函数同步 Protocol 字段;修改 `internal/handler/provider_handler.go` : CreateProvider 和 UpdateProvider 的请求结构体新增 Protocol 字段(可选,默认 "openai"),创建/更新 Provider 时赋值 Protocol 字段, List/Get 响应中包含 Protocol 字段;更新 `internal/service/service_test.go` 中所有创建测试 Provider 的地方补充 Protocol 字段;更新 `internal/handler/handler_test.go` 中 Provider CRUD 测试的请求体补充 Protocol 字段;创建数据库迁移文件 `backend/migrations/YYYYMMDDHHMMSS_add_provider_protocol.sql` : ALTER TABLE providers ADD COLUMN protocol TEXT DEFAULT 'openai'
- [x ] 6.2 重写 `internal/provider/client.go` :定义 HTTPRequestSpec 和 HTTPResponseSpec( 或引用 conversion 包的定义),简化 ProviderClient 接口为 Send(ctx, HTTPRequestSpec) → (*HTTPResponseSpec, error) 和 SendStream(ctx, HTTPRequestSpec) → (<-chan StreamEvent, error),移除所有旧协议 硬编码依赖, Send 方法直接使用 http.NewRequest + spec.URL/Headers/Body, SendStream 保留现有 readStream goroutine 逻辑但输入改为 HTTPRequestSpec; 重写 `provider/client_test.go` :删除所有基于旧协议类型的 测试用例,基于 HTTPRequestSpec 重写成功/失败/流式测试用例,使用 httptest.Server 验证请求构建和响应解析
- [x ] 6.3 创建 `internal/handler/proxy_handler.go` :实现 ProxyHandler struct( 依赖 ConversionEngine、ProviderClient、RoutingService、StatsService) , 实现 HandleProxy(w, r) 方法:从 URL 提取 clientProtocol( 仅支持 `/{protocol}/v1/...` 前缀路由,不支持旧路由)、解析请求体 JSON、调用 RoutingService.Route(modelName) 获取路由结果(含 Provider.Protocol 作为 providerProtocol) 、构建 TargetProvider、调用 engine.convertHttpRequest、调用 providerClient.Send/SendStream、调用 engine.convertHttpResponse、设置响应 Content-Type 和状态码、流式处理设置 text/event-stream 并用 StreamConverter 逐块转换写入、错误处理使用 clientAdapter.encodeError、异步调用 StatsService.Record; 编写测试使用 httptest + mock engine/client/service
- [x ] 6.4 修改 `cmd/server/main.go` :创建 AdapterRegistry 并注册 OpenAI 和 Anthropic Adapter、创建 ConversionEngine( 注入 registry) 、创建 ProxyHandler( 注入 engine + providerClient + routingService + statsService) 、配置 Gin 路由:新增 `/{protocol}/v1/{path:*}` → ProxyHandler.HandleProxy, 删除旧路由 `/v1/chat/completions` 和 `/v1/messages` ,移除旧的 OpenAIHandler 和 AnthropicHandler 的路由注册,删 除旧 Adapter 创建代码
## 7. 清理和文档
- [ ] 7.1 删除旧代码:删除 `internal/protocol/openai/` 目录( types.go, adapter.go, adapter_test.go) 、删除 `internal/protocol/anthropic/` 目录( types.go, converter.go, converter_test.go, stream_converter.go, stream_converter_test.go) 、删除 `internal/handler/openai_handler.go` 和 `internal/handler/anthropic_handler.go` 、删除 `internal/handler/handler_test.go` 中旧 OpenAI/Anthropic handler 测试用例和旧 `mockProviderClient` (基于 openai.ChatCompletionRequest 的签名)、重写 `handler_test.go` 为 ProxyHandler 测试(基于新 ProviderClient 接口和 ConversionEngine mock) 、删除 `internal/protocol/` 空目录、确认所有编译通过且无残留 import
- [ ] 7.2 更新 `README.md` :更新项目结构说明(新增 internal/conversion/、删除 internal/protocol/)、更新 API 接口说明(代理接口变更:`/{protocol}/v1/...` ,移除旧路由 `/v1/chat/completions` 和 `/v1/messages` ) 、更新配置说明( Provider 新增 protocol 字段)
- [ ] 7.3 端到端测试:在 `backend/tests/integration/` 中新增 `conversion_test.go` ,使用 httptest mock 上游服务器验证完整请求流: OpenAI→OpenAI 同协议透传、Anthropic→Anthropic 同协议透传、OpenAI→Anthropic 跨协议非流式、Anthropic→OpenAI 跨协议非流式、4 种方向的流式转换(含 tool_calls 和 thinking) 、Models 接口跨协议转换、错误响应格式验证(各协议格式)、旧路由 `/v1/chat/completions` 和 `/v1/messages` 返回 404; 复用 `tests/helpers.go` 中的测试数据库和 Provider/Model 创建辅助函数
- [x ] 7.1 删除旧代码:删除 `internal/protocol/openai/` 目录( types.go, adapter.go, adapter_test.go) 、删除 `internal/protocol/anthropic/` 目录( types.go, converter.go, converter_test.go, stream_converter.go, stream_converter_test.go) 、删除 `internal/handler/openai_handler.go` 和 `internal/handler/anthropic_handler.go` 、删除 `internal/handler/handler_test.go` 中旧 OpenAI/Anthropic handler 测试用例和旧 `mockProviderClient` (基于旧协议类型 的签名)、重写 `handler_test.go` 为 ProxyHandler 测试(基于新 ProviderClient 接口和 ConversionEngine mock) 、删除 `internal/protocol/` 空目录、确认所有编译通过且无残留 import
- [x ] 7.2 更新 `README.md` :更新项目结构说明(新增 internal/conversion/、删除 internal/protocol/)、更新 API 接口说明(代理接口变更:`/{protocol}/v1/...` ,移除旧路由 `/v1/chat/completions` 和 `/v1/messages` ) 、更新配置说明( Provider 新增 protocol 字段)
- [x ] 7.3 端到端测试:在 `backend/tests/integration/` 中新增 `conversion_test.go` ,使用 httptest mock 上游服务器验证完整请求流: OpenAI→OpenAI 同协议透传、Anthropic→Anthropic 同协议透传、OpenAI→Anthropic 跨协议非流式、Anthropic→OpenAI 跨协议非流式、4 种方向的流式转换(含 tool_calls 和 thinking) 、Models 接口跨协议转换、错误响应格式验证(各协议格式)、旧路由 `/v1/chat/completions` 和 `/v1/messages` 返回 404; 复用 `tests/helpers.go` 中的测试数据库和 Provider/Model 创建辅助函数