fix: preserve explicit zero values in native relay requests - #3069
Conversation
WalkthroughPR adds documentation Rule 6 on preserving explicit zero values in request DTOs using pointers with omitempty, then systematically converts scalar fields in request DTO structs from value types to pointer types (Stream, MaxTokens, TopP, etc.), updates relay handlers and channel adaptors to safely access these pointers via the Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~35 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (11)
relay/channel/claude/relay-claude.go (4)
86-88:⚠️ Potential issue | 🟡 MinorUse
common.Unmarshalinstead ofjson.Unmarshal.As per coding guidelines, all JSON unmarshal operations must use wrapper functions from
common/json.go.🔧 Suggested fix
// 解析 UserLocation JSON var userLocationMap map[string]interface{} - if err := json.Unmarshal(textRequest.WebSearchOptions.UserLocation, &userLocationMap); err == nil { + if err := common.Unmarshal(textRequest.WebSearchOptions.UserLocation, &userLocationMap); err == nil {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@relay/channel/claude/relay-claude.go` around lines 86 - 88, Replace the direct call to json.Unmarshal when decoding textRequest.WebSearchOptions.UserLocation into userLocationMap with the project's wrapper common.Unmarshal; specifically, locate the block that declares var userLocationMap map[string]interface{} and currently calls json.Unmarshal(textRequest.WebSearchOptions.UserLocation, &userLocationMap) and change it to use common.Unmarshal(...) handling the returned error the same way (check error != nil). Ensure imports are updated to remove "encoding/json" if no longer used and to reference the common package used for JSON helpers.
821-825:⚠️ Potential issue | 🟡 MinorUse
common.Marshalinstead ofjson.Marshal.As per coding guidelines, all JSON marshal operations must use wrapper functions from
common/json.go.🔧 Suggested fix
case types.RelayFormatOpenAI: openaiResponse := ResponseClaude2OpenAI(&claudeResponse) openaiResponse.Usage = *claudeInfo.Usage - responseData, err = json.Marshal(openaiResponse) + responseData, err = common.Marshal(openaiResponse)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@relay/channel/claude/relay-claude.go` around lines 821 - 825, Replace the direct json.Marshal call with the project's wrapper by calling common.Marshal on the OpenAI response: in the block that builds openaiResponse (using ResponseClaude2OpenAI, claudeResponse, claudeInfo, openaiResponse) swap json.Marshal(openaiResponse) for common.Marshal(openaiResponse) and keep the existing error handling (return types.NewError(err, types.ErrorCodeBadResponseBody)) so behavior remains identical while adhering to the common/json.go wrapper.
374-377:⚠️ Potential issue | 🟡 MinorUse
common.Unmarshalinstead ofjson.Unmarshal.As per coding guidelines, all JSON unmarshal operations must use wrapper functions from
common/json.go.🔧 Suggested fix
if message.ToolCalls != nil { for _, toolCall := range message.ParseToolCalls() { inputObj := make(map[string]any) - if err := json.Unmarshal([]byte(toolCall.Function.Arguments), &inputObj); err != nil { + if err := common.Unmarshal([]byte(toolCall.Function.Arguments), &inputObj); err != nil {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@relay/channel/claude/relay-claude.go` around lines 374 - 377, Replace the direct call to json.Unmarshal when parsing toolCall.Function.Arguments with the project wrapper common.Unmarshal: call common.Unmarshal([]byte(toolCall.Function.Arguments), &inputObj) and handle the returned error the same way (using the existing err variable and logging via common.SysLog). Ensure the common package is imported/available in relay-claude.go and reference the existing symbols ParseToolCalls, toolCall.Function.Arguments, and inputObj when making the change.
510-510:⚠️ Potential issue | 🟡 MinorUse
common.Marshalinstead ofjson.Marshal.As per coding guidelines, all JSON marshal operations must use wrapper functions from
common/json.go.🔧 Suggested fix
case "tool_use": - args, _ := json.Marshal(message.Input) + args, _ := common.Marshal(message.Input)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@relay/channel/claude/relay-claude.go` at line 510, Replace the direct call to json.Marshal for serializing message.Input with the project's wrapper common.Marshal: change the call in the code that assigns to args (currently args, _ := json.Marshal(message.Input)) to use common.Marshal(message.Input), capture and handle the returned error instead of discarding it, and propagate or log the error appropriately where args is used (referencing the args variable and message.Input and using common.Marshal in place of json.Marshal).relay/channel/minimax/adaptor.go (1)
58-67:⚠️ Potential issue | 🟡 MinorUse
common.Unmarshalandcommon.Marshalinstead ofjsonpackage.As per coding guidelines, all JSON marshal/unmarshal operations must use wrapper functions from
common/json.go.🔧 Suggested fix
+ "github.com/QuantumNous/new-api/common" "github.com/QuantumNous/new-api/dto"// 同步扩展字段的厂商自定义metadata if len(request.Metadata) > 0 { - if err := json.Unmarshal(request.Metadata, &minimaxRequest); err != nil { + if err := common.Unmarshal(request.Metadata, &minimaxRequest); err != nil { return nil, fmt.Errorf("error unmarshalling metadata to minimax request: %w", err) } } - jsonData, err := json.Marshal(minimaxRequest) + jsonData, err := common.Marshal(minimaxRequest) if err != nil { return nil, fmt.Errorf("error marshalling minimax request: %w", err) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@relay/channel/minimax/adaptor.go` around lines 58 - 67, Replace direct json package calls with the project's JSON wrappers: use common.Unmarshal to decode request.Metadata into minimaxRequest (keeping the same error wrapping message) and use common.Marshal to encode minimaxRequest into jsonData (again preserving the error wrap). Update the two sites where json.Unmarshal and json.Marshal are used—refer to minimaxRequest and request.Metadata—to call common.Unmarshal(request.Metadata, &minimaxRequest) and common.Marshal(minimaxRequest) and propagate errors with the existing fmt.Errorf messages.relay/channel/tencent/relay-tencent.go (2)
196-196:⚠️ Potential issue | 🟡 MinorUse
common.Marshal()instead ofjson.Marshal.Direct usage of
json.MarshalingetTencentSignviolates coding guidelines.Proposed fix
- payload, _ := json.Marshal(req) + payload, _ := common.Marshal(req)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@relay/channel/tencent/relay-tencent.go` at line 196, Replace the direct call to json.Marshal in getTencentSign with the project's common.Marshal helper: use common.Marshal(req) to produce payload (error-handling as appropriate) instead of json.Marshal(req); update the payload variable assignment and handle the returned error from common.Marshal consistently with surrounding error handling in getTencentSign.
143-143:⚠️ Potential issue | 🟡 MinorUse
common.Unmarshal()instead ofjson.Unmarshal.Direct usage of
json.Unmarshalviolates coding guidelines.Proposed fix
- err = json.Unmarshal(responseBody, &tencentSb) + err = common.Unmarshal(responseBody, &tencentSb)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@relay/channel/tencent/relay-tencent.go` at line 143, Replace the direct call to json.Unmarshal(responseBody, &tencentSb) with the project-standard common.Unmarshal helper: call common.Unmarshal(responseBody, &tencentSb) (or the equivalent common.UnmarshalBytes) to parse responseBody into tencentSb so the code follows the coding guidelines and centralized error handling; update imports if necessary to remove "encoding/json" and ensure common is imported.relay/channel/ali/rerank.go (2)
67-67:⚠️ Potential issue | 🟡 MinorUse
common.Marshal()instead ofjson.Marshal.Direct usage of
json.Marshalviolates coding guidelines.Proposed fix
- jsonResponse, err := json.Marshal(rerankResponse) + jsonResponse, err := common.Marshal(rerankResponse)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@relay/channel/ali/rerank.go` at line 67, Replace the direct call to json.Marshal with the project's wrapper common.Marshal for serializing rerankResponse: change json.Marshal(rerankResponse) to common.Marshal(rerankResponse), update imports to remove encoding/json if no longer used and add the common package import, and keep the existing error handling around the marshal call intact (i.e., still check the returned error and handle it as before). Ensure the variable names (jsonResponse, rerankResponse) and surrounding logic in rerank.go remain unchanged except for swapping the marshal function.
43-43:⚠️ Potential issue | 🟡 MinorUse
common.Unmarshal()instead ofjson.Unmarshal.Direct usage of
json.Unmarshalviolates coding guidelines. As per coding guidelines: "All JSON marshal/unmarshal operations MUST use wrapper functions fromcommon/json.go".Proposed fix
- err = json.Unmarshal(responseBody, &aliResponse) + err = common.Unmarshal(responseBody, &aliResponse)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@relay/channel/ali/rerank.go` at line 43, Replace the direct call to json.Unmarshal(responseBody, &aliResponse) with the project's JSON wrapper: call common.Unmarshal(responseBody, &aliResponse) (and ensure the common package is imported), handling and returning the same error value as before; update any error checks around aliResponse unmarshal to use the error returned by common.Unmarshal in rerank.go so behavior remains identical.relay/helper/valid_request.go (1)
155-169:⚠️ Potential issue | 🟠 MajorNegative multipart
ncan overflow into a huge unsigned value.
String2Int("-1")becomes-1, and casting touintyields a very large number, bypassing the defaulting logic.🔧 Suggested fix
-imageRequest.N = common.GetPointer(uint(common.String2Int(formData.Get("n")))) +nVal := common.String2Int(formData.Get("n")) +if nVal <= 0 { + imageRequest.N = common.GetPointer(uint(1)) +} else { + imageRequest.N = common.GetPointer(uint(nVal)) +} ... -if imageRequest.N == nil || *imageRequest.N == 0 { - imageRequest.N = common.GetPointer(uint(1)) -}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@relay/helper/valid_request.go` around lines 155 - 169, The code casts the parsed signed int from common.String2Int(formData.Get("n")) directly to uint causing negative values (e.g., "-1") to become huge unsigned numbers and bypass the default; fix by first storing the parsed value in a signed int (e.g., parsedN := common.String2Int(...)), then check if parsedN <= 0 and set imageRequest.N = common.GetPointer(uint(1)) in that case, otherwise set imageRequest.N = common.GetPointer(uint(parsedN)); update the logic around imageRequest.N assignment in the function handling form parsing (references: imageRequest.N, common.String2Int, common.GetPointer) so negatives and zero are guarded against before any uint cast.relay/channel/ollama/relay-ollama.go (1)
520-522:⚠️ Potential issue | 🟡 MinorUse
common.Unmarshalinstead ofjson.Unmarshal.This violates the coding guideline requiring all JSON unmarshal operations to use wrapper functions from
common/json.go.Proposed fix
- if err := json.Unmarshal(body, &versionResp); err != nil { + if err := common.Unmarshal(body, &versionResp); err != nil {As per coding guidelines: "Use
common.Unmarshal()fromcommon/json.gofor all JSON marshal/unmarshal operations in business code. Do NOT directly import or callencoding/jsonfor marshal/unmarshal in business code."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@relay/channel/ollama/relay-ollama.go` around lines 520 - 522, Replace the direct call to json.Unmarshal with the project's wrapper common.Unmarshal: call common.Unmarshal(body, &versionResp) and propagate the error similarly (e.g., return "", fmt.Errorf("解析响应失败: %v", err)) so the behavior/format stays the same; update imports to remove direct usage of encoding/json if no longer needed and ensure the file imports the package that exposes Unmarshal (common) so the change affects the json unmarshal in the function that handles the version response (where versionResp and body are used).
🧹 Nitpick comments (6)
relay/channel/replicate/adaptor.go (1)
5-5: Directencoding/jsonusage violates coding guidelines.Line 5 imports
encoding/jsonand line 114 callsjson.Unmarshaldirectly. Per coding guidelines, all JSON operations must use wrapper functions fromcommon/json.go.Proposed fix
Remove the direct
encoding/jsonimport and replacejson.Unmarshalwithcommon.Unmarshal:import ( "bytes" - "encoding/json" "errors" "fmt"if len(request.OutputFormat) > 0 { var outputFormat string - if err := json.Unmarshal(request.OutputFormat, &outputFormat); err == nil && strings.TrimSpace(outputFormat) != "" { + if err := common.Unmarshal(request.OutputFormat, &outputFormat); err == nil && strings.TrimSpace(outputFormat) != "" { inputPayload["output_format"] = outputFormat } }As per coding guidelines: "Do NOT directly import or call
encoding/jsonfor marshal/unmarshal in business code."Also applies to: 114-117
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@relay/channel/replicate/adaptor.go` at line 5, Remove the direct import of "encoding/json" and replace the direct call to json.Unmarshal (used around the block that includes function/method invoking json.Unmarshal) with the wrapper common.Unmarshal from common/json.go; update the import list to include the common package instead of encoding/json and ensure any error handling around the Unmarshal call remains the same while calling common.Unmarshal(...) where json.Unmarshal(...) was used.controller/relay.go (1)
266-276: Logic is correct; consider consistent helper usage for readability.The pointer-safe access via
lo.FromPtrOrcorrectly handles the DTO fields that are now pointers. However, line 276 useslo.FromPtrwhile other cases uselo.FromPtrOr(..., uint(0)). Both are functionally equivalent for*uint(returning 0 when nil), but using a consistent pattern improves readability.♻️ Optional: use consistent helper for ClaudeRequest case
case *dto.ClaudeRequest: - meta.MaxTokens = int(lo.FromPtr(r.MaxTokens)) + meta.MaxTokens = int(lo.FromPtrOr(r.MaxTokens, uint(0)))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@controller/relay.go` around lines 266 - 276, The ClaudeRequest branch currently uses lo.FromPtr(r.MaxTokens) while other branches use lo.FromPtrOr(..., uint(0)); update the dto.ClaudeRequest handling to use lo.FromPtrOr(r.MaxTokens, uint(0)) when setting meta.MaxTokens so the pointer-safe helper usage is consistent with the other cases (leave the assignment to meta.MaxTokens and the int cast as-is).service/openaicompat/chat_to_responses.go (1)
370-373: Redundant pointer conversion for TopP.The current code dereferences the pointer with
lo.FromPtr, then immediately wraps it back in a pointer withcommon.GetPointer. This is equivalent to just copying the pointer value.♻️ Simplified TopP handling
var topP *float64 if req.TopP != nil { - topP = common.GetPointer(lo.FromPtr(req.TopP)) + v := *req.TopP + topP = &v }Or if you want to keep using helpers:
var topP *float64 if req.TopP != nil { - topP = common.GetPointer(lo.FromPtr(req.TopP)) + topP = lo.ToPtr(*req.TopP) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@service/openaicompat/chat_to_responses.go` around lines 370 - 373, The TopP handling is performing a redundant dereference and rewrap: in the block that defines topP, remove the lo.FromPtr + common.GetPointer dance and simply copy the pointer (assign topP = req.TopP) so you preserve the original *float64; update the code around the topP variable initialization (referencing topP and req.TopP, and remove lo.FromPtr and common.GetPointer usage) to eliminate the unnecessary conversion.relay/image_handler.go (1)
140-142: Redundant condition check.Since
imageNis auintthat defaults to 1 and can only be overwritten by dereferencing a non-nil pointer, the conditionimageN > 0will always be true. Consider removing the conditional check.♻️ Suggested simplification
- if imageN > 0 { - logContent = append(logContent, fmt.Sprintf("生成数量 %d", imageN)) - } + logContent = append(logContent, fmt.Sprintf("生成数量 %d", imageN))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@relay/image_handler.go` around lines 140 - 142, The conditional check `if imageN > 0` is redundant; remove the `if` and always append the generated-count entry to `logContent` by calling `logContent = append(logContent, fmt.Sprintf("生成数量 %d", imageN))` unconditionally (update the code around `imageN`/`logContent` in `image_handler.go` accordingly).dto/embedding.go (1)
11-20: Consider aligningEmbeddingOptionswith Rule 6 pattern.
EmbeddingOptionshasSeedandTopKas non-pointerintwithomitempty, which means explicit zero values would be silently dropped during marshal. If this struct is used in upstream relay contexts, consider converting these to*intfor consistency with Rule 6.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@dto/embedding.go` around lines 11 - 20, EmbeddingOptions currently declares Seed and TopK as non-pointer ints so zero values are omitted by json.Marshal due to `omitempty`; change Seed and TopK to pointer types (`*int`) in the EmbeddingOptions struct so explicit zero values are preserved (consistent with Rule 6), update any constructors/usage sites that set or read Seed and TopK to handle nil vs non-nil correctly, and add nil-checks or dereferencing where these fields are consumed (e.g., places referencing EmbeddingOptions.Seed or .TopK).dto/openai_request_zero_value_test.go (1)
37-50: Assert exact zero/false values, not only key presence.These checks currently prove that keys survive marshaling, but not that values remain
0/false. Add value assertions to fully lock the behavior.🧪 Suggested test hardening
require.True(t, gjson.GetBytes(encoded, "stream").Exists()) +require.Equal(t, false, gjson.GetBytes(encoded, "stream").Bool()) require.True(t, gjson.GetBytes(encoded, "max_tokens").Exists()) +require.Equal(t, float64(0), gjson.GetBytes(encoded, "max_tokens").Num()) require.True(t, gjson.GetBytes(encoded, "top_p").Exists()) +require.Equal(t, float64(0), gjson.GetBytes(encoded, "top_p").Num())Also applies to: 69-72
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@dto/openai_request_zero_value_test.go` around lines 37 - 50, Replace presence-only assertions in dto/openai_request_zero_value_test.go with exact-value assertions using gjson.GetBytes(encoded, "<key>").Int() or .Bool() as appropriate: assert numeric keys (max_tokens, max_completion_tokens, top_p, top_k, n, frequency_penalty, presence_penalty, seed, logprobs, top_logprobs, dimensions) equal 0 and boolean keys (stream, return_images, return_related_questions) equal false using require.Equal/require.False/require.Zero; update the similar checks at the later block mentioned (lines 69-72) the same way so the test verifies zero/false values rather than mere key existence.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@relay/channel/aws/dto.go`:
- Around line 97-109: The mapping currently treats explicit zero values as
absent because each gate checks "*req.<Field> != 0" before copying; change the
logic in the block that sets novaReq.InferenceConfig so each field is included
when the request pointer is non-nil (remove the "*... != 0" checks and only test
for nil), and update NovaInferenceConfig's scalar fields to be pointer types (or
remove omitempty) so zeros are preserved when marshaling; ensure
novaReq.InferenceConfig = &NovaInferenceConfig{} is allocated once and then
assign pointer values (e.g., set MaxTokens to a pointer to int when
req.MaxTokens != nil) so explicit 0 values are propagated.
In `@relay/channel/gemini/relay-gemini.go`:
- Around line 216-219: The current check `if textRequest.Seed != nil &&
*textRequest.Seed != 0` drops an explicitly provided zero seed; change the guard
to only test for nil (i.e., `if textRequest.Seed != nil`) and then convert and
assign the seed as you do now (`geminiSeed :=
int64(lo.FromPtr(textRequest.Seed))` and `geminiRequest.GenerationConfig.Seed =
common.GetPointer(geminiSeed)`), so an explicit 0 value is preserved when
converting from textRequest to geminiRequest.GenerationConfig.Seed.
In `@relay/channel/openai/adaptor.go`:
- Around line 318-321: The code treats an explicit max_completion_tokens: 0 as
missing because it compares dereferenced-or-default values; change the condition
to check pointer nils instead so a user-specified zero is preserved. Replace the
current if that uses lo.FromPtrOr on request.MaxCompletionTokens with a
nil-check: only copy request.MaxTokens into request.MaxCompletionTokens when
request.MaxCompletionTokens == nil and request.MaxTokens != nil, then set
request.MaxTokens = nil (refer to request.MaxCompletionTokens and
request.MaxTokens in adaptor.go).
In `@relay/channel/siliconflow/adaptor.go`:
- Around line 56-59: The code treats sfRequest.BatchSize==0 as "unset" and
therefore overwrites an explicit zero with request.N; change the absence check
to use a sentinel (e.g. initialize BatchSize to -1 where sfRequest is created)
and only copy from request.N when sfRequest.BatchSize == -1, or alternatively
add a boolean flag like BatchSizeSet and check that instead; update the
conditional around sfRequest.BatchSize, request.N and lo.FromPtr(request.N) in
the adaptor.go block so explicit zero values are preserved.
In `@relay/channel/vertex/adaptor.go`:
- Line 307: Replace the direct call to json.Unmarshal(request.ExtraBody, &extra)
with the project's wrapper common.Unmarshal(request.ExtraBody, &extra),
preserving the existing error-checking logic; update the import usage (remove
direct json usage if unused) and ensure the error return from common.Unmarshal
is handled exactly as before where it currently checks err == nil around
request.ExtraBody and the variable extra.
In `@service/convert.go`:
- Around line 711-719: The conversion currently ignores explicit zero values
because it checks `> 0`; remove the `> 0` tests and only check for non-nil
before assigning so that zero is preserved: for
`geminiRequest.GenerationConfig.TopP` and `TopK` and `MaxOutputTokens` check `!=
nil` and then set `openaiRequest.TopP =
lo.ToPtr(*geminiRequest.GenerationConfig.TopP)`, `openaiRequest.TopK =
lo.ToPtr(int(*geminiRequest.GenerationConfig.TopK))`, and
`openaiRequest.MaxTokens =
lo.ToPtr(*geminiRequest.GenerationConfig.MaxOutputTokens)` respectively (apply
same change to the other similar block referenced).
---
Outside diff comments:
In `@relay/channel/ali/rerank.go`:
- Line 67: Replace the direct call to json.Marshal with the project's wrapper
common.Marshal for serializing rerankResponse: change
json.Marshal(rerankResponse) to common.Marshal(rerankResponse), update imports
to remove encoding/json if no longer used and add the common package import, and
keep the existing error handling around the marshal call intact (i.e., still
check the returned error and handle it as before). Ensure the variable names
(jsonResponse, rerankResponse) and surrounding logic in rerank.go remain
unchanged except for swapping the marshal function.
- Line 43: Replace the direct call to json.Unmarshal(responseBody, &aliResponse)
with the project's JSON wrapper: call common.Unmarshal(responseBody,
&aliResponse) (and ensure the common package is imported), handling and
returning the same error value as before; update any error checks around
aliResponse unmarshal to use the error returned by common.Unmarshal in rerank.go
so behavior remains identical.
In `@relay/channel/claude/relay-claude.go`:
- Around line 86-88: Replace the direct call to json.Unmarshal when decoding
textRequest.WebSearchOptions.UserLocation into userLocationMap with the
project's wrapper common.Unmarshal; specifically, locate the block that declares
var userLocationMap map[string]interface{} and currently calls
json.Unmarshal(textRequest.WebSearchOptions.UserLocation, &userLocationMap) and
change it to use common.Unmarshal(...) handling the returned error the same way
(check error != nil). Ensure imports are updated to remove "encoding/json" if no
longer used and to reference the common package used for JSON helpers.
- Around line 821-825: Replace the direct json.Marshal call with the project's
wrapper by calling common.Marshal on the OpenAI response: in the block that
builds openaiResponse (using ResponseClaude2OpenAI, claudeResponse, claudeInfo,
openaiResponse) swap json.Marshal(openaiResponse) for
common.Marshal(openaiResponse) and keep the existing error handling (return
types.NewError(err, types.ErrorCodeBadResponseBody)) so behavior remains
identical while adhering to the common/json.go wrapper.
- Around line 374-377: Replace the direct call to json.Unmarshal when parsing
toolCall.Function.Arguments with the project wrapper common.Unmarshal: call
common.Unmarshal([]byte(toolCall.Function.Arguments), &inputObj) and handle the
returned error the same way (using the existing err variable and logging via
common.SysLog). Ensure the common package is imported/available in
relay-claude.go and reference the existing symbols ParseToolCalls,
toolCall.Function.Arguments, and inputObj when making the change.
- Line 510: Replace the direct call to json.Marshal for serializing
message.Input with the project's wrapper common.Marshal: change the call in the
code that assigns to args (currently args, _ := json.Marshal(message.Input)) to
use common.Marshal(message.Input), capture and handle the returned error instead
of discarding it, and propagate or log the error appropriately where args is
used (referencing the args variable and message.Input and using common.Marshal
in place of json.Marshal).
In `@relay/channel/minimax/adaptor.go`:
- Around line 58-67: Replace direct json package calls with the project's JSON
wrappers: use common.Unmarshal to decode request.Metadata into minimaxRequest
(keeping the same error wrapping message) and use common.Marshal to encode
minimaxRequest into jsonData (again preserving the error wrap). Update the two
sites where json.Unmarshal and json.Marshal are used—refer to minimaxRequest and
request.Metadata—to call common.Unmarshal(request.Metadata, &minimaxRequest) and
common.Marshal(minimaxRequest) and propagate errors with the existing fmt.Errorf
messages.
In `@relay/channel/ollama/relay-ollama.go`:
- Around line 520-522: Replace the direct call to json.Unmarshal with the
project's wrapper common.Unmarshal: call common.Unmarshal(body, &versionResp)
and propagate the error similarly (e.g., return "", fmt.Errorf("解析响应失败: %v",
err)) so the behavior/format stays the same; update imports to remove direct
usage of encoding/json if no longer needed and ensure the file imports the
package that exposes Unmarshal (common) so the change affects the json unmarshal
in the function that handles the version response (where versionResp and body
are used).
In `@relay/channel/tencent/relay-tencent.go`:
- Line 196: Replace the direct call to json.Marshal in getTencentSign with the
project's common.Marshal helper: use common.Marshal(req) to produce payload
(error-handling as appropriate) instead of json.Marshal(req); update the payload
variable assignment and handle the returned error from common.Marshal
consistently with surrounding error handling in getTencentSign.
- Line 143: Replace the direct call to json.Unmarshal(responseBody, &tencentSb)
with the project-standard common.Unmarshal helper: call
common.Unmarshal(responseBody, &tencentSb) (or the equivalent
common.UnmarshalBytes) to parse responseBody into tencentSb so the code follows
the coding guidelines and centralized error handling; update imports if
necessary to remove "encoding/json" and ensure common is imported.
In `@relay/helper/valid_request.go`:
- Around line 155-169: The code casts the parsed signed int from
common.String2Int(formData.Get("n")) directly to uint causing negative values
(e.g., "-1") to become huge unsigned numbers and bypass the default; fix by
first storing the parsed value in a signed int (e.g., parsedN :=
common.String2Int(...)), then check if parsedN <= 0 and set imageRequest.N =
common.GetPointer(uint(1)) in that case, otherwise set imageRequest.N =
common.GetPointer(uint(parsedN)); update the logic around imageRequest.N
assignment in the function handling form parsing (references: imageRequest.N,
common.String2Int, common.GetPointer) so negatives and zero are guarded against
before any uint cast.
---
Nitpick comments:
In `@controller/relay.go`:
- Around line 266-276: The ClaudeRequest branch currently uses
lo.FromPtr(r.MaxTokens) while other branches use lo.FromPtrOr(..., uint(0));
update the dto.ClaudeRequest handling to use lo.FromPtrOr(r.MaxTokens, uint(0))
when setting meta.MaxTokens so the pointer-safe helper usage is consistent with
the other cases (leave the assignment to meta.MaxTokens and the int cast as-is).
In `@dto/embedding.go`:
- Around line 11-20: EmbeddingOptions currently declares Seed and TopK as
non-pointer ints so zero values are omitted by json.Marshal due to `omitempty`;
change Seed and TopK to pointer types (`*int`) in the EmbeddingOptions struct so
explicit zero values are preserved (consistent with Rule 6), update any
constructors/usage sites that set or read Seed and TopK to handle nil vs non-nil
correctly, and add nil-checks or dereferencing where these fields are consumed
(e.g., places referencing EmbeddingOptions.Seed or .TopK).
In `@dto/openai_request_zero_value_test.go`:
- Around line 37-50: Replace presence-only assertions in
dto/openai_request_zero_value_test.go with exact-value assertions using
gjson.GetBytes(encoded, "<key>").Int() or .Bool() as appropriate: assert numeric
keys (max_tokens, max_completion_tokens, top_p, top_k, n, frequency_penalty,
presence_penalty, seed, logprobs, top_logprobs, dimensions) equal 0 and boolean
keys (stream, return_images, return_related_questions) equal false using
require.Equal/require.False/require.Zero; update the similar checks at the later
block mentioned (lines 69-72) the same way so the test verifies zero/false
values rather than mere key existence.
In `@relay/channel/replicate/adaptor.go`:
- Line 5: Remove the direct import of "encoding/json" and replace the direct
call to json.Unmarshal (used around the block that includes function/method
invoking json.Unmarshal) with the wrapper common.Unmarshal from common/json.go;
update the import list to include the common package instead of encoding/json
and ensure any error handling around the Unmarshal call remains the same while
calling common.Unmarshal(...) where json.Unmarshal(...) was used.
In `@relay/image_handler.go`:
- Around line 140-142: The conditional check `if imageN > 0` is redundant;
remove the `if` and always append the generated-count entry to `logContent` by
calling `logContent = append(logContent, fmt.Sprintf("生成数量 %d", imageN))`
unconditionally (update the code around `imageN`/`logContent` in
`image_handler.go` accordingly).
In `@service/openaicompat/chat_to_responses.go`:
- Around line 370-373: The TopP handling is performing a redundant dereference
and rewrap: in the block that defines topP, remove the lo.FromPtr +
common.GetPointer dance and simply copy the pointer (assign topP = req.TopP) so
you preserve the original *float64; update the code around the topP variable
initialization (referencing topP and req.TopP, and remove lo.FromPtr and
common.GetPointer usage) to eliminate the unnecessary conversion.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (52)
.cursor/rules/project.mdcAGENTS.mdCLAUDE.mdcontroller/channel-test.gocontroller/relay.godto/audio.godto/claude.godto/embedding.godto/gemini.godto/gemini_generation_config_test.godto/openai_image.godto/openai_request.godto/openai_request_zero_value_test.godto/rerank.gorelay/channel/ali/image.gorelay/channel/ali/image_wan.gorelay/channel/ali/rerank.gorelay/channel/ali/text.gorelay/channel/aws/dto.gorelay/channel/baidu/relay-baidu.gorelay/channel/claude/relay-claude.gorelay/channel/cloudflare/relay_cloudflare.gorelay/channel/codex/adaptor.gorelay/channel/cohere/relay-cohere.gorelay/channel/coze/relay-coze.gorelay/channel/dify/relay-dify.gorelay/channel/gemini/adaptor.gorelay/channel/gemini/relay-gemini.gorelay/channel/minimax/adaptor.gorelay/channel/mistral/text.gorelay/channel/ollama/relay-ollama.gorelay/channel/openai/adaptor.gorelay/channel/perplexity/adaptor.gorelay/channel/perplexity/relay-perplexity.gorelay/channel/replicate/adaptor.gorelay/channel/siliconflow/adaptor.gorelay/channel/tencent/relay-tencent.gorelay/channel/vertex/adaptor.gorelay/channel/vertex/dto.gorelay/channel/volcengine/adaptor.gorelay/channel/xai/adaptor.gorelay/channel/xunfei/relay-xunfei.gorelay/channel/zhipu/adaptor.gorelay/channel/zhipu/relay-zhipu.gorelay/channel/zhipu_4v/adaptor.gorelay/channel/zhipu_4v/relay-zhipu_v4.gorelay/claude_handler.gorelay/compatible_handler.gorelay/helper/valid_request.gorelay/image_handler.goservice/convert.goservice/openaicompat/chat_to_responses.go
| if (req.MaxTokens != nil && *req.MaxTokens != 0) || (req.Temperature != nil && *req.Temperature != 0) || (req.TopP != nil && *req.TopP != 0) || (req.TopK != nil && *req.TopK != 0) || req.Stop != nil { | ||
| novaReq.InferenceConfig = &NovaInferenceConfig{} | ||
| if req.MaxTokens != 0 { | ||
| novaReq.InferenceConfig.MaxTokens = int(req.MaxTokens) | ||
| if req.MaxTokens != nil && *req.MaxTokens != 0 { | ||
| novaReq.InferenceConfig.MaxTokens = int(*req.MaxTokens) | ||
| } | ||
| if req.Temperature != nil && *req.Temperature != 0 { | ||
| novaReq.InferenceConfig.Temperature = *req.Temperature | ||
| } | ||
| if req.TopP != 0 { | ||
| novaReq.InferenceConfig.TopP = req.TopP | ||
| if req.TopP != nil && *req.TopP != 0 { | ||
| novaReq.InferenceConfig.TopP = *req.TopP | ||
| } | ||
| if req.TopK != 0 { | ||
| novaReq.InferenceConfig.TopK = req.TopK | ||
| if req.TopK != nil && *req.TopK != 0 { | ||
| novaReq.InferenceConfig.TopK = *req.TopK |
There was a problem hiding this comment.
Explicit zero values are still being filtered out in Nova mapping.
Line 97/99/105/108 still gate on *req.<field> != 0, so requests that explicitly set 0 are treated as omitted. This contradicts the PR goal and changes behavior for clients relying on explicit zero.
Proposed fix
- if (req.MaxTokens != nil && *req.MaxTokens != 0) || (req.Temperature != nil && *req.Temperature != 0) || (req.TopP != nil && *req.TopP != 0) || (req.TopK != nil && *req.TopK != 0) || req.Stop != nil {
+ if req.MaxTokens != nil || req.Temperature != nil || req.TopP != nil || req.TopK != nil || req.Stop != nil {
novaReq.InferenceConfig = &NovaInferenceConfig{}
- if req.MaxTokens != nil && *req.MaxTokens != 0 {
+ if req.MaxTokens != nil {
novaReq.InferenceConfig.MaxTokens = int(*req.MaxTokens)
}
- if req.Temperature != nil && *req.Temperature != 0 {
+ if req.Temperature != nil {
novaReq.InferenceConfig.Temperature = *req.Temperature
}
- if req.TopP != nil && *req.TopP != 0 {
+ if req.TopP != nil {
novaReq.InferenceConfig.TopP = *req.TopP
}
- if req.TopK != nil && *req.TopK != 0 {
+ if req.TopK != nil {
novaReq.InferenceConfig.TopK = *req.TopK
}Also, to truly preserve zero in outbound JSON, NovaInferenceConfig scalar fields should be pointers (or omitempty removed), otherwise zeros are still dropped at marshal time.
📝 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.
| if (req.MaxTokens != nil && *req.MaxTokens != 0) || (req.Temperature != nil && *req.Temperature != 0) || (req.TopP != nil && *req.TopP != 0) || (req.TopK != nil && *req.TopK != 0) || req.Stop != nil { | |
| novaReq.InferenceConfig = &NovaInferenceConfig{} | |
| if req.MaxTokens != 0 { | |
| novaReq.InferenceConfig.MaxTokens = int(req.MaxTokens) | |
| if req.MaxTokens != nil && *req.MaxTokens != 0 { | |
| novaReq.InferenceConfig.MaxTokens = int(*req.MaxTokens) | |
| } | |
| if req.Temperature != nil && *req.Temperature != 0 { | |
| novaReq.InferenceConfig.Temperature = *req.Temperature | |
| } | |
| if req.TopP != 0 { | |
| novaReq.InferenceConfig.TopP = req.TopP | |
| if req.TopP != nil && *req.TopP != 0 { | |
| novaReq.InferenceConfig.TopP = *req.TopP | |
| } | |
| if req.TopK != 0 { | |
| novaReq.InferenceConfig.TopK = req.TopK | |
| if req.TopK != nil && *req.TopK != 0 { | |
| novaReq.InferenceConfig.TopK = *req.TopK | |
| if req.MaxTokens != nil || req.Temperature != nil || req.TopP != nil || req.TopK != nil || req.Stop != nil { | |
| novaReq.InferenceConfig = &NovaInferenceConfig{} | |
| if req.MaxTokens != nil { | |
| novaReq.InferenceConfig.MaxTokens = int(*req.MaxTokens) | |
| } | |
| if req.Temperature != nil { | |
| novaReq.InferenceConfig.Temperature = *req.Temperature | |
| } | |
| if req.TopP != nil { | |
| novaReq.InferenceConfig.TopP = *req.TopP | |
| } | |
| if req.TopK != nil { | |
| novaReq.InferenceConfig.TopK = *req.TopK |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@relay/channel/aws/dto.go` around lines 97 - 109, The mapping currently treats
explicit zero values as absent because each gate checks "*req.<Field> != 0"
before copying; change the logic in the block that sets novaReq.InferenceConfig
so each field is included when the request pointer is non-nil (remove the "*...
!= 0" checks and only test for nil), and update NovaInferenceConfig's scalar
fields to be pointer types (or remove omitempty) so zeros are preserved when
marshaling; ensure novaReq.InferenceConfig = &NovaInferenceConfig{} is allocated
once and then assign pointer values (e.g., set MaxTokens to a pointer to int
when req.MaxTokens != nil) so explicit 0 values are propagated.
| if textRequest.Seed != nil && *textRequest.Seed != 0 { | ||
| geminiSeed := int64(lo.FromPtr(textRequest.Seed)) | ||
| geminiRequest.GenerationConfig.Seed = common.GetPointer(geminiSeed) | ||
| } |
There was a problem hiding this comment.
Explicit seed: 0 is currently dropped during OpenAI→Gemini conversion.
The != 0 guard turns an explicitly provided zero into “absent”. If zero is intentional, this breaks request fidelity.
🔧 Suggested fix
-if textRequest.Seed != nil && *textRequest.Seed != 0 {
- geminiSeed := int64(lo.FromPtr(textRequest.Seed))
+if textRequest.Seed != nil {
+ geminiSeed := int64(*textRequest.Seed)
geminiRequest.GenerationConfig.Seed = common.GetPointer(geminiSeed)
}📝 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.
| if textRequest.Seed != nil && *textRequest.Seed != 0 { | |
| geminiSeed := int64(lo.FromPtr(textRequest.Seed)) | |
| geminiRequest.GenerationConfig.Seed = common.GetPointer(geminiSeed) | |
| } | |
| if textRequest.Seed != nil { | |
| geminiSeed := int64(*textRequest.Seed) | |
| geminiRequest.GenerationConfig.Seed = common.GetPointer(geminiSeed) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@relay/channel/gemini/relay-gemini.go` around lines 216 - 219, The current
check `if textRequest.Seed != nil && *textRequest.Seed != 0` drops an explicitly
provided zero seed; change the guard to only test for nil (i.e., `if
textRequest.Seed != nil`) and then convert and assign the seed as you do now
(`geminiSeed := int64(lo.FromPtr(textRequest.Seed))` and
`geminiRequest.GenerationConfig.Seed = common.GetPointer(geminiSeed)`), so an
explicit 0 value is preserved when converting from textRequest to
geminiRequest.GenerationConfig.Seed.
| if lo.FromPtrOr(request.MaxCompletionTokens, uint(0)) == 0 && lo.FromPtrOr(request.MaxTokens, uint(0)) != 0 { | ||
| request.MaxCompletionTokens = request.MaxTokens | ||
| request.MaxTokens = 0 | ||
| request.MaxTokens = nil | ||
| } |
There was a problem hiding this comment.
max_completion_tokens: 0 is treated as missing and overwritten.
The current condition merges explicit zero with nil, so user intent can be lost when max_tokens is present.
🔧 Suggested fix
-if lo.FromPtrOr(request.MaxCompletionTokens, uint(0)) == 0 && lo.FromPtrOr(request.MaxTokens, uint(0)) != 0 {
+if request.MaxCompletionTokens == nil && lo.FromPtrOr(request.MaxTokens, uint(0)) != 0 {
request.MaxCompletionTokens = request.MaxTokens
request.MaxTokens = nil
}📝 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.
| if lo.FromPtrOr(request.MaxCompletionTokens, uint(0)) == 0 && lo.FromPtrOr(request.MaxTokens, uint(0)) != 0 { | |
| request.MaxCompletionTokens = request.MaxTokens | |
| request.MaxTokens = 0 | |
| request.MaxTokens = nil | |
| } | |
| if request.MaxCompletionTokens == nil && lo.FromPtrOr(request.MaxTokens, uint(0)) != 0 { | |
| request.MaxCompletionTokens = request.MaxTokens | |
| request.MaxTokens = nil | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@relay/channel/openai/adaptor.go` around lines 318 - 321, The code treats an
explicit max_completion_tokens: 0 as missing because it compares
dereferenced-or-default values; change the condition to check pointer nils
instead so a user-specified zero is preserved. Replace the current if that uses
lo.FromPtrOr on request.MaxCompletionTokens with a nil-check: only copy
request.MaxTokens into request.MaxCompletionTokens when
request.MaxCompletionTokens == nil and request.MaxTokens != nil, then set
request.MaxTokens = nil (refer to request.MaxCompletionTokens and
request.MaxTokens in adaptor.go).
| if sfRequest.BatchSize == 0 { | ||
| sfRequest.BatchSize = request.N | ||
| if request.N != nil { | ||
| sfRequest.BatchSize = lo.FromPtr(request.N) | ||
| } |
There was a problem hiding this comment.
Preserve explicit batch_size: 0 instead of treating it as missing.
This fallback uses sfRequest.BatchSize == 0 as the absence check, so an explicitly provided zero can be overwritten by n, which breaks the explicit-zero preservation intent.
💡 Proposed fix
sfRequest.Model = request.Model
sfRequest.Prompt = request.Prompt
// 优先使用image_size/batch_size,否则使用OpenAI标准的size/n
if sfRequest.ImageSize == "" {
sfRequest.ImageSize = request.Size
}
- if sfRequest.BatchSize == 0 {
- if request.N != nil {
- sfRequest.BatchSize = lo.FromPtr(request.N)
- }
- }
+ _, hasBatchSize := request.Extra["batch_size"]
+ if !hasBatchSize && sfRequest.BatchSize == 0 && request.N != nil {
+ sfRequest.BatchSize = lo.FromPtr(request.N)
+ }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@relay/channel/siliconflow/adaptor.go` around lines 56 - 59, The code treats
sfRequest.BatchSize==0 as "unset" and therefore overwrites an explicit zero with
request.N; change the absence check to use a sentinel (e.g. initialize BatchSize
to -1 where sfRequest is created) and only copy from request.N when
sfRequest.BatchSize == -1, or alternatively add a boolean flag like BatchSizeSet
and check that instead; update the conditional around sfRequest.BatchSize,
request.N and lo.FromPtr(request.N) in the adaptor.go block so explicit zero
values are preserved.
| @@ -305,7 +306,7 @@ func (a *Adaptor) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayIn | |||
| var extra map[string]any | |||
| if err := json.Unmarshal(request.ExtraBody, &extra); err == nil { | |||
There was a problem hiding this comment.
Use common.Unmarshal() instead of json.Unmarshal.
Direct usage of json.Unmarshal violates coding guidelines. As per coding guidelines: "All JSON marshal/unmarshal operations MUST use wrapper functions from common/json.go".
Proposed fix
- if err := json.Unmarshal(request.ExtraBody, &extra); err == nil {
+ if err := common.Unmarshal(request.ExtraBody, &extra); err == nil {📝 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.
| if err := json.Unmarshal(request.ExtraBody, &extra); err == nil { | |
| if err := common.Unmarshal(request.ExtraBody, &extra); err == nil { |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@relay/channel/vertex/adaptor.go` at line 307, Replace the direct call to
json.Unmarshal(request.ExtraBody, &extra) with the project's wrapper
common.Unmarshal(request.ExtraBody, &extra), preserving the existing
error-checking logic; update the import usage (remove direct json usage if
unused) and ensure the error return from common.Unmarshal is handled exactly as
before where it currently checks err == nil around request.ExtraBody and the
variable extra.
| if geminiRequest.GenerationConfig.TopP != nil && *geminiRequest.GenerationConfig.TopP > 0 { | ||
| openaiRequest.TopP = lo.ToPtr(*geminiRequest.GenerationConfig.TopP) | ||
| } | ||
| if geminiRequest.GenerationConfig.TopK > 0 { | ||
| openaiRequest.TopK = int(geminiRequest.GenerationConfig.TopK) | ||
| if geminiRequest.GenerationConfig.TopK != nil && *geminiRequest.GenerationConfig.TopK > 0 { | ||
| openaiRequest.TopK = lo.ToPtr(int(*geminiRequest.GenerationConfig.TopK)) | ||
| } | ||
| if geminiRequest.GenerationConfig.MaxOutputTokens > 0 { | ||
| openaiRequest.MaxTokens = geminiRequest.GenerationConfig.MaxOutputTokens | ||
| if geminiRequest.GenerationConfig.MaxOutputTokens != nil && *geminiRequest.GenerationConfig.MaxOutputTokens > 0 { | ||
| openaiRequest.MaxTokens = lo.ToPtr(*geminiRequest.GenerationConfig.MaxOutputTokens) | ||
| } |
There was a problem hiding this comment.
Gemini→OpenAI conversion currently drops explicit zero values.
These > 0 guards discard non-nil zero inputs, so explicit 0 is not preserved through conversion.
🔧 Suggested fix
-if geminiRequest.GenerationConfig.TopP != nil && *geminiRequest.GenerationConfig.TopP > 0 {
+if geminiRequest.GenerationConfig.TopP != nil {
openaiRequest.TopP = lo.ToPtr(*geminiRequest.GenerationConfig.TopP)
}
-if geminiRequest.GenerationConfig.TopK != nil && *geminiRequest.GenerationConfig.TopK > 0 {
+if geminiRequest.GenerationConfig.TopK != nil {
openaiRequest.TopK = lo.ToPtr(int(*geminiRequest.GenerationConfig.TopK))
}
-if geminiRequest.GenerationConfig.MaxOutputTokens != nil && *geminiRequest.GenerationConfig.MaxOutputTokens > 0 {
+if geminiRequest.GenerationConfig.MaxOutputTokens != nil {
openaiRequest.MaxTokens = lo.ToPtr(*geminiRequest.GenerationConfig.MaxOutputTokens)
}
-if geminiRequest.GenerationConfig.CandidateCount != nil && *geminiRequest.GenerationConfig.CandidateCount > 0 {
+if geminiRequest.GenerationConfig.CandidateCount != nil {
openaiRequest.N = lo.ToPtr(*geminiRequest.GenerationConfig.CandidateCount)
}Also applies to: 724-726
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@service/convert.go` around lines 711 - 719, The conversion currently ignores
explicit zero values because it checks `> 0`; remove the `> 0` tests and only
check for non-nil before assigning so that zero is preserved: for
`geminiRequest.GenerationConfig.TopP` and `TopK` and `MaxOutputTokens` check `!=
nil` and then set `openaiRequest.TopP =
lo.ToPtr(*geminiRequest.GenerationConfig.TopP)`, `openaiRequest.TopK =
lo.ToPtr(int(*geminiRequest.GenerationConfig.TopK))`, and
`openaiRequest.MaxTokens =
lo.ToPtr(*geminiRequest.GenerationConfig.MaxOutputTokens)` respectively (apply
same change to the other similar block referenced).
…nore fix: preserve explicit zero values in native relay requests
Summary by CodeRabbit
Release Notes
Documentation
Tests
Bug Fixes