Skip to content

PR #252 优化#254

Closed
hging wants to merge 1 commit intomainfrom
issue-251
Closed

PR #252 优化#254
hging wants to merge 1 commit intomainfrom
issue-251

Conversation

@hging
Copy link
Contributor

@hging hging commented Feb 25, 2026

Summary:

  • Added internal/codexutil/normalize.go with shared input normalization (role
    cleanup, function_call id prefixing with fc_, uuid fallback, output defaulting).
  • Wired both Codex adapters to use the shared helper and removed duplicated logic.
  • Updated TestApplyCodexRequestTuning to cover fc_ prefixing, generated IDs, and
    defaulted function_call_output output.
  • Verified Store remains json:"store,omitempty".

Test:

  • go test ./internal/adapter/provider/codex -run TestApplyCodexRequestTuning

Files touched:

  • internal/codexutil/normalize.go
  • internal/adapter/provider/cliproxyapi_codex/adapter.go
  • internal/adapter/provider/codex/adapter.go
  • internal/adapter/provider/codex/adapter_test.go

Summary by CodeRabbit

发版说明

  • 重构

    • 整合了有效负载规范化逻辑至统一工具函数,改善了代码组织和可维护性。
  • 测试

    • 增强了测试覆盖范围,包含更复杂的输入有效负载和ID前缀验证。

@coderabbitai
Copy link

coderabbitai bot commented Feb 25, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 284bc77 and a188bc1.

📒 Files selected for processing (4)
  • internal/adapter/provider/cliproxyapi_codex/adapter.go
  • internal/adapter/provider/codex/adapter.go
  • internal/adapter/provider/codex/adapter_test.go
  • internal/codexutil/normalize.go

📝 Walkthrough

概述

将 Codex 有效载荷规范化逻辑从多个适配器中的内联实现迁移到集中的 codexutil.NormalizeCodexInput 实用函数,以统一处理输入数组规范化、角色字段删除和函数调用 ID 前缀添加。

更改

内聚组 / 文件 摘要
适配器重构
internal/adapter/provider/cliproxyapi_codex/adapter.go, internal/adapter/provider/codex/adapter.go
codexutil.NormalizeCodexInput 调用替换内联有效载荷规范化逻辑,删除 gjson 和 sjson 依赖项,保留现有的令牌/身份验证流程。
规范化实用程序
internal/codexutil/normalize.go
引入新的导出函数 NormalizeCodexInput,处理输入数组元素的类型检查、角色字段删除、函数调用 ID 前缀添加(带 uuid 生成)和函数调用输出默认值设置。
适配器测试更新
internal/adapter/provider/codex/adapter_test.go
扩展测试有效载荷以覆盖复杂场景:多个函数调用、函数调用输出和工具输入 ID;新增断言验证 ID 前缀、默认输出值和多个输入条目的角色处理。

估计代码审查工作量

🎯 3 (中等) | ⏱️ ~20 分钟

可能相关的 PR

建议的审查者

  • ymkiux
  • awsl233777

🐰 规范化的魔法在此聚集,
复杂的逻辑从各处汇合,
一个函数统一了混乱的舞蹈,
ID 闪烁着 uuid 的光芒,
适配器们轻声鸣谢~

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch issue-251

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
internal/adapter/provider/codex/adapter_test.go (1)

39-44: 建议补一个“max_tokensmax_output_tokens 同时存在”的优先级用例

当前断言验证了迁移路径,但还没覆盖冲突输入场景。建议新增用例明确“已存在 max_tokens 时不被 max_output_tokens 覆盖”,可避免后续回归。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/adapter/provider/codex/adapter_test.go` around lines 39 - 44,
为避免回归,请新增一个优先级用例(例如 TestTunedMaxTokensPriority)在输入同时包含 max_tokens 和
max_output_tokens 时断言:经过迁移后 max_output_tokens 被移除(使用 gjson.GetBytes(tuned,
"max_output_tokens").Exists() 为 false),但已有的 max_tokens 不被覆盖(使用
gjson.GetBytes(tuned, "max_tokens").Int() 等于原始设定值);在测试中构造包含两者的原始 JSON
并调用当前迁移/处理函数以验证这些断言。
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/codexutil/normalize.go`:
- Around line 25-38: 在处理 function_call 的分支中,确保即便 id 已有 "fc_" 前缀但包含前后空白也会被修正:对
item.Get("id").String() 做 strings.TrimSpace(id) 后,如果 strings.HasPrefix(trimmed,
"fc_") 仍需用 sjson.SetBytes 将去空白后的值写回(例如 "fc_"+trimmedWithoutPrefix 或直接
trimmed),并保持现有对空 id 的生成逻辑;在处理 function_call_output 的分支,不仅检查
item.Get("output").Exists(),还要识别 output 为 JSON null(例如通过 item.Get("output").Type
== gjson.Null 或检查 item.Get("output").Raw == "null")并在这两种情况下把 output 写回为 ""(使用
sjson.SetBytes),以消除 {"output":null} 的边界情况。

In `@internal/converter/claude_to_codex.go`:
- Line 31: The struct field Store is being set to the boolean zero value but is
tagged with `omitempty`, so it is omitted from JSON and cannot force
"store:false"; change the model to distinguish “unset” vs “explicit false” by
making Store a pointer (*bool) or a nullable type, and ensure serialization
emits "store": false when explicitly false (alternatively, after marshaling the
request object, inject the "store": false key into the JSON map/string before
sending). Update all codepaths that construct the request (where Store is
assigned) and any unmarshaling/validation logic to handle the new
pointer/nullable type (look for uses of the Store field and the function that
builds/serializes the Claude->Codex request).

---

Nitpick comments:
In `@internal/adapter/provider/codex/adapter_test.go`:
- Around line 39-44: 为避免回归,请新增一个优先级用例(例如 TestTunedMaxTokensPriority)在输入同时包含
max_tokens 和 max_output_tokens 时断言:经过迁移后 max_output_tokens 被移除(使用
gjson.GetBytes(tuned, "max_output_tokens").Exists() 为 false),但已有的 max_tokens
不被覆盖(使用 gjson.GetBytes(tuned, "max_tokens").Int() 等于原始设定值);在测试中构造包含两者的原始 JSON
并调用当前迁移/处理函数以验证这些断言。

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fd93783 and 284bc77.

📒 Files selected for processing (5)
  • internal/adapter/provider/cliproxyapi_codex/adapter.go
  • internal/adapter/provider/codex/adapter.go
  • internal/adapter/provider/codex/adapter_test.go
  • internal/codexutil/normalize.go
  • internal/converter/claude_to_codex.go
📜 Review details
🧰 Additional context used
🧬 Code graph analysis (3)
internal/adapter/provider/codex/adapter.go (1)
internal/codexutil/normalize.go (1)
  • NormalizeCodexInput (12-43)
internal/converter/claude_to_codex.go (1)
internal/converter/types_codex.go (2)
  • CodexInputItem (23-32)
  • CodexOutput (57-66)
internal/adapter/provider/cliproxyapi_codex/adapter.go (1)
internal/codexutil/normalize.go (1)
  • NormalizeCodexInput (12-43)
🔇 Additional comments (4)
internal/converter/claude_to_codex.go (2)

94-121: tool_use/tool_result 到 Codex 输入项的映射清晰且方向正确

这里把 function_callfunction_call_output 分开构造,并保留 CallID,可读性和兼容性都比内联拼装更好。


204-215: 响应侧 ID/CallID 的双轨映射实现合理

ID 统一为 fc_ 前缀、CallID 保留调用语义,和请求侧策略保持一致,利于上下游对齐。

internal/adapter/provider/codex/adapter.go (1)

565-577: 请求调优与标准化顺序合理

先做 max_output_tokens 兼容迁移,再统一走 NormalizeCodexInput,可避免字段冲突并减少重复逻辑,改动方向正确。

internal/adapter/provider/cliproxyapi_codex/adapter.go (1)

231-258: 在执行前统一做 Codex payload 归一化是正确改动

这让 CLIProxyAPI 路径与主 Codex 适配器的输入语义保持一致,能减少同类请求在不同通道下的行为差异。

Comment on lines +25 to +38
if itemType == "function_call" {
id := strings.TrimSpace(item.Get("id").String())
switch {
case strings.HasPrefix(id, "fc_"):
case id == "":
body, _ = sjson.SetBytes(body, fmt.Sprintf("input.%d.id", i), "fc_"+uuid.NewString())
default:
body, _ = sjson.SetBytes(body, fmt.Sprintf("input.%d.id", i), "fc_"+id)
}
}
if itemType == "function_call_output" {
if !item.Get("output").Exists() {
body, _ = sjson.SetBytes(body, fmt.Sprintf("input.%d.output", i), "")
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

归一化对“带空白的已前缀 ID”和 output:null 仍有边界遗漏

当前逻辑在 id 已是 fc_ 前缀时不会回写去空白值;同时只判断 output 是否存在会漏掉 {"output":null}。这会让“看起来已规范化”的输入仍带异常值。

建议修复示例
 		if itemType == "function_call" {
-			id := strings.TrimSpace(item.Get("id").String())
+			rawID := item.Get("id").String()
+			id := strings.TrimSpace(rawID)
 			switch {
 			case strings.HasPrefix(id, "fc_"):
+				if rawID != id {
+					body, _ = sjson.SetBytes(body, fmt.Sprintf("input.%d.id", i), id)
+				}
 			case id == "":
 				body, _ = sjson.SetBytes(body, fmt.Sprintf("input.%d.id", i), "fc_"+uuid.NewString())
 			default:
 				body, _ = sjson.SetBytes(body, fmt.Sprintf("input.%d.id", i), "fc_"+id)
 			}
 		}
 		if itemType == "function_call_output" {
-			if !item.Get("output").Exists() {
+			out := item.Get("output")
+			if !out.Exists() || out.Raw == "null" {
 				body, _ = sjson.SetBytes(body, fmt.Sprintf("input.%d.output", i), "")
 			}
 		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if itemType == "function_call" {
id := strings.TrimSpace(item.Get("id").String())
switch {
case strings.HasPrefix(id, "fc_"):
case id == "":
body, _ = sjson.SetBytes(body, fmt.Sprintf("input.%d.id", i), "fc_"+uuid.NewString())
default:
body, _ = sjson.SetBytes(body, fmt.Sprintf("input.%d.id", i), "fc_"+id)
}
}
if itemType == "function_call_output" {
if !item.Get("output").Exists() {
body, _ = sjson.SetBytes(body, fmt.Sprintf("input.%d.output", i), "")
}
if itemType == "function_call" {
rawID := item.Get("id").String()
id := strings.TrimSpace(rawID)
switch {
case strings.HasPrefix(id, "fc_"):
if rawID != id {
body, _ = sjson.SetBytes(body, fmt.Sprintf("input.%d.id", i), id)
}
case id == "":
body, _ = sjson.SetBytes(body, fmt.Sprintf("input.%d.id", i), "fc_"+uuid.NewString())
default:
body, _ = sjson.SetBytes(body, fmt.Sprintf("input.%d.id", i), "fc_"+id)
}
}
if itemType == "function_call_output" {
out := item.Get("output")
if !out.Exists() || out.Raw == "null" {
body, _ = sjson.SetBytes(body, fmt.Sprintf("input.%d.output", i), "")
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/codexutil/normalize.go` around lines 25 - 38, 在处理 function_call
的分支中,确保即便 id 已有 "fc_" 前缀但包含前后空白也会被修正:对 item.Get("id").String() 做
strings.TrimSpace(id) 后,如果 strings.HasPrefix(trimmed, "fc_") 仍需用 sjson.SetBytes
将去空白后的值写回(例如 "fc_"+trimmedWithoutPrefix 或直接 trimmed),并保持现有对空 id 的生成逻辑;在处理
function_call_output 的分支,不仅检查 item.Get("output").Exists(),还要识别 output 为 JSON
null(例如通过 item.Get("output").Type == gjson.Null 或检查 item.Get("output").Raw ==
"null")并在这两种情况下把 output 写回为 ""(使用 sjson.SetBytes),以消除 {"output":null} 的边界情况。

MaxOutputTokens: req.MaxTokens,
Temperature: req.Temperature,
TopP: req.TopP,
Store: false,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Store: falseomitempty 下不会落到最终 JSON,无法真正“强制关闭存储”

Line 31 仅设置布尔零值;若 Store 字段带 json:",omitempty",序列化时会被省略。这样上游若默认不是 false,就无法保证行为一致。建议在序列化后显式写入 store:false(或改字段建模为可区分“未设置/显式 false”的类型)。

建议修复示例
 import (
 	"encoding/json"
 	"strings"
 	"time"
 
 	"github.com/awsl-project/maxx/internal/domain"
+	"github.com/tidwall/sjson"
 )
@@
-	return json.Marshal(codexReq)
+	encoded, err := json.Marshal(codexReq)
+	if err != nil {
+		return nil, err
+	}
+	encoded, _ = sjson.SetBytes(encoded, "store", false)
+	return encoded, nil
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/converter/claude_to_codex.go` at line 31, The struct field Store is
being set to the boolean zero value but is tagged with `omitempty`, so it is
omitted from JSON and cannot force "store:false"; change the model to
distinguish “unset” vs “explicit false” by making Store a pointer (*bool) or a
nullable type, and ensure serialization emits "store": false when explicitly
false (alternatively, after marshaling the request object, inject the "store":
false key into the JSON map/string before sending). Update all codepaths that
construct the request (where Store is assigned) and any unmarshaling/validation
logic to handle the new pointer/nullable type (look for uses of the Store field
and the function that builds/serializes the Claude->Codex request).

@hging hging closed this Feb 25, 2026
@ymkiux ymkiux deleted the issue-251 branch February 25, 2026 08:18
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.

1 participant