Skip to content

Commit b6e8a4e

Browse files
Merge pull request #8 from inflearn/feature/ci-lint-cleanup
chore: clean up lint findings in fork-authored code
2 parents 1511593 + 0500202 commit b6e8a4e

8 files changed

Lines changed: 40 additions & 36 deletions

internal/endpointspec/endpointspec.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ func (GeminiGenerateContentEndpointSpec) ParseBody(
518518
return "", nil, false, nil, fmt.Errorf("%w: failed to parse JSON for Gemini generateContent: %w", internalapi.ErrMalformedRequest, err)
519519
}
520520
// Model and Stream are json:"-" fields populated by the processor from path-derived headers.
521-
return internalapi.OriginalModel(req.Model), &req, req.Stream, nil, nil
521+
return req.Model, &req, req.Stream, nil, nil
522522
}
523523

524524
// ParseMultipartBody implements [Spec.ParseMultipartBody]. Gemini generateContent is JSON-only.
@@ -530,7 +530,7 @@ func (GeminiGenerateContentEndpointSpec) ParseMultipartBody([]byte, string, bool
530530
func (GeminiGenerateContentEndpointSpec) GetTranslator(schema filterapi.VersionedAPISchema, modelNameOverride string) (translator.GeminiGenerateContentTranslator, error) {
531531
switch schema.Name {
532532
case filterapi.APISchemaGCPVertexAI:
533-
return translator.NewGeminiToGCPVertexAITranslator(internalapi.ModelNameOverride(modelNameOverride)), nil
533+
return translator.NewGeminiToGCPVertexAITranslator(modelNameOverride), nil
534534
default:
535535
return nil, fmt.Errorf("unsupported API schema for Gemini generateContent: backend=%s", schema)
536536
}
@@ -562,7 +562,7 @@ func (GeminiCachedContentsEndpointSpec) ParseBody(
562562
}
563563
model := normalizeVertexModelName(req.Model)
564564
// cachedContents is never streamed.
565-
return internalapi.OriginalModel(model), &req, false, nil, nil
565+
return model, &req, false, nil, nil
566566
}
567567

568568
// normalizeVertexModelName trims any Vertex AI resource prefix from a model identifier and
@@ -587,7 +587,7 @@ func (GeminiCachedContentsEndpointSpec) ParseMultipartBody([]byte, string, bool)
587587
func (GeminiCachedContentsEndpointSpec) GetTranslator(schema filterapi.VersionedAPISchema, modelNameOverride string) (translator.GeminiCachedContentsTranslator, error) {
588588
switch schema.Name {
589589
case filterapi.APISchemaGCPVertexAI:
590-
return translator.NewGeminiCachedContentsToGCPVertexAITranslator(internalapi.ModelNameOverride(modelNameOverride)), nil
590+
return translator.NewGeminiCachedContentsToGCPVertexAITranslator(modelNameOverride), nil
591591
default:
592592
return nil, fmt.Errorf("unsupported API schema for Gemini cachedContents: backend=%s", schema)
593593
}
@@ -804,9 +804,7 @@ func (SpeechEndpointSpec) GetTranslator(
804804
modelNameOverride,
805805
), nil
806806
case filterapi.APISchemaAlibabaDashScope:
807-
return translator.NewSpeechOpenAIToDashScopeTranslator(
808-
internalapi.ModelNameOverride(modelNameOverride),
809-
), nil
807+
return translator.NewSpeechOpenAIToDashScopeTranslator(modelNameOverride), nil
810808
default:
811809
return nil, fmt.Errorf("unsupported API schema for speech: backend=%s", schema)
812810
}

internal/endpointspec/endpointspec_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import (
1515
"google.golang.org/genai"
1616
"k8s.io/utils/ptr"
1717

18-
gcpschema "github.com/envoyproxy/ai-gateway/internal/apischema/gcp"
1918
cohereschema "github.com/envoyproxy/ai-gateway/internal/apischema/cohere"
19+
gcpschema "github.com/envoyproxy/ai-gateway/internal/apischema/gcp"
2020
"github.com/envoyproxy/ai-gateway/internal/apischema/openai"
2121
"github.com/envoyproxy/ai-gateway/internal/filterapi"
2222
"github.com/envoyproxy/ai-gateway/internal/json"
@@ -1137,7 +1137,7 @@ func TestGeminiGenerateContentEndpointSpec_ParseBody(t *testing.T) {
11371137
require.NoError(t, err)
11381138
// Model and Stream are json:"-" fields — they are empty after unmarshaling.
11391139
// The processor fills them from synthetic headers later.
1140-
require.Equal(t, "", model)
1140+
require.Empty(t, model)
11411141
require.False(t, stream)
11421142
require.NotNil(t, parsed)
11431143
require.Nil(t, mutated)
@@ -1539,7 +1539,7 @@ func TestGeminiCachedContentsEndpointSpec_ParseBody(t *testing.T) {
15391539
t.Run("empty body (GET/DELETE) returns zero value", func(t *testing.T) {
15401540
model, req, stream, mutated, err := spec.ParseBody(nil, false)
15411541
require.NoError(t, err)
1542-
require.Equal(t, "", string(model))
1542+
require.Empty(t, model)
15431543
require.NotNil(t, req)
15441544
require.False(t, stream)
15451545
require.Nil(t, mutated)
@@ -1549,7 +1549,7 @@ func TestGeminiCachedContentsEndpointSpec_ParseBody(t *testing.T) {
15491549
body := []byte(`{"model":"projects/p/locations/us-central1/publishers/google/models/gemini-1.5-pro","ttl":"3600s"}`)
15501550
model, req, stream, _, err := spec.ParseBody(body, false)
15511551
require.NoError(t, err)
1552-
require.Equal(t, "gemini-1.5-pro", string(model), "OriginalModel must be the short name so AIGatewayRoute headers match")
1552+
require.Equal(t, "gemini-1.5-pro", model, "OriginalModel must be the short name so AIGatewayRoute headers match")
15531553
require.NotNil(t, req)
15541554
// The body struct keeps the original full path for the translator to act on.
15551555
require.Equal(t, "projects/p/locations/us-central1/publishers/google/models/gemini-1.5-pro", req.Model)
@@ -1561,7 +1561,7 @@ func TestGeminiCachedContentsEndpointSpec_ParseBody(t *testing.T) {
15611561
body := []byte(`{"model":"gemini-2.5-flash","ttl":"60s"}`)
15621562
model, _, _, _, err := spec.ParseBody(body, false)
15631563
require.NoError(t, err)
1564-
require.Equal(t, "gemini-2.5-flash", string(model))
1564+
require.Equal(t, "gemini-2.5-flash", model)
15651565
})
15661566

15671567
t.Run("invalid JSON returns malformed request", func(t *testing.T) {

internal/extproc/server_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,10 +1106,11 @@ func TestServer_RegisterPrefix_FallbackToNextEntry(t *testing.T) {
11061106
return nil
11071107
}
11081108
after := path[idx+len(seg):]
1109-
if !strings.Contains(after, ":") {
1109+
model, _, ok := strings.Cut(after, ":")
1110+
if !ok {
11101111
return nil
11111112
}
1112-
return map[string]string{"x-aigw-path-model": after[:strings.Index(after, ":")]}
1113+
return map[string]string{"x-aigw-path-model": model}
11131114
})
11141115

11151116
cacheProc := &mockProcessor{}

internal/translator/gemini_cachedcontents_gcpvertexai.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func (g *geminiCachedContentsToGCPVertexAITranslator) RequestBody(
7777
if body != nil && body.Model != "" {
7878
desired := body.Model
7979
if g.modelNameOverride != "" {
80-
desired = rewriteVertexModelName(desired, string(g.modelNameOverride))
80+
desired = rewriteVertexModelName(desired, g.modelNameOverride)
8181
}
8282
desired = expandToVertexFullModelPath(desired, os.Getenv(envGCPProject), os.Getenv(envGCPLocation))
8383
if desired != body.Model {

internal/translator/gemini_gcpvertexai.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,17 @@ func NewGeminiToGCPVertexAITranslator(modelNameOverride internalapi.ModelNameOve
4949
func (g *geminiToGCPVertexAITranslator) RequestBody(_ []byte, body *gcp.GenerateContentRequest, _ bool) (
5050
newHeaders []internalapi.Header, newBody []byte, err error,
5151
) {
52-
g.requestModel = internalapi.RequestModel(body.Model)
52+
g.requestModel = body.Model
5353
if g.modelNameOverride != "" {
5454
g.requestModel = g.modelNameOverride
5555
}
5656
g.stream = body.Stream
5757

5858
var path string
5959
if g.stream {
60-
path = buildGCPModelPathSuffix(gcpModelPublisherGoogle, string(g.requestModel), gcpMethodStreamGenerateContent, "alt=sse")
60+
path = buildGCPModelPathSuffix(gcpModelPublisherGoogle, g.requestModel, gcpMethodStreamGenerateContent, "alt=sse")
6161
} else {
62-
path = buildGCPModelPathSuffix(gcpModelPublisherGoogle, string(g.requestModel), gcpMethodGenerateContent)
62+
path = buildGCPModelPathSuffix(gcpModelPublisherGoogle, g.requestModel, gcpMethodGenerateContent)
6363
}
6464

6565
// Re-marshal: json:"-" fields (Model, Stream) are not serialised.
@@ -108,7 +108,7 @@ func (g *geminiToGCPVertexAITranslator) ResponseBody(_ map[string]string, body i
108108
}
109109

110110
if gcpResp.ModelVersion != "" {
111-
responseModel = internalapi.ResponseModel(gcpResp.ModelVersion)
111+
responseModel = gcpResp.ModelVersion
112112
}
113113

114114
if u := gcpResp.UsageMetadata; u != nil {

internal/translator/imageedit_openai_openai.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func (o *openAIToOpenAIImageEditsTranslator) RequestBody(original []byte, p *ope
5151
if bErr != nil {
5252
return nil, nil, fmt.Errorf("failed to extract multipart boundary for model override: %w", bErr)
5353
}
54-
newBody, err = rebuildMultipartWithModelOverride(original, boundary, string(o.modelNameOverride))
54+
newBody, err = rebuildMultipartWithModelOverride(original, boundary, o.modelNameOverride)
5555
if err != nil {
5656
return nil, nil, fmt.Errorf("failed to rebuild multipart with model override: %w", err)
5757
}
@@ -110,7 +110,8 @@ func extractMultipartBoundary(body []byte) (string, error) {
110110
if eol < 3 || !bytes.HasPrefix(body, []byte("--")) {
111111
return "", fmt.Errorf("invalid multipart body: missing boundary marker")
112112
}
113-
return string(body[2:eol]), nil
113+
// The guard above ensures 2 <= eol, so the slice bounds are safe.
114+
return string(body[2:eol]), nil //nolint:gosec // G602 false positive; eol >= 3 is enforced above.
114115
}
115116

116117
// rebuildMultipartWithModelOverride rebuilds the multipart body with the given model value

internal/translator/openai_speech_dashscope.go

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -116,16 +116,21 @@ type openAIToDashScopeSpeechTranslator struct {
116116
// {"model":"qwen3-tts-flash","input":{"text":"hello","voice":"Cherry","language_type":"Auto"}}
117117
//
118118
// Voice, instructions, response_format, speed, and stream_format are not translated:
119-
// - voice: passed through verbatim — the AIGatewayRoute owner is expected to supply a
120-
// DashScope-side voice name (e.g. "Cherry"); OpenAI voice presets do not have a natural
121-
// mapping and forcing one here would silently pick the wrong timbre.
122-
// - instructions/speed: DashScope has no equivalent.
123-
// - response_format: DashScope's non-streaming response is always WAV via URL; ignored here
124-
// and the outbound content-type is set to audio/wav in ResponseHeaders.
125-
// - stream_format: only non-streaming is implemented in this first cut; SSE support would
126-
// require calling DashScope's streaming synthesis API (different endpoint) and is out of
127-
// scope until we see demand.
128-
func (o *openAIToDashScopeSpeechTranslator) RequestBody(original []byte, req *openai.SpeechRequest, forceBodyMutation bool) (
119+
// - voice: passed through verbatim — the AIGatewayRoute owner is expected to supply a
120+
// DashScope-side voice name (e.g. "Cherry"); OpenAI voice presets do not have a natural
121+
// mapping and forcing one here would silently pick the wrong timbre.
122+
// - instructions/speed: DashScope has no equivalent.
123+
// - response_format: DashScope's non-streaming response is always WAV via URL; ignored here
124+
// and the outbound content-type is set to audio/wav in ResponseHeaders.
125+
// - stream_format: only non-streaming is implemented in this first cut; SSE support would
126+
// require calling DashScope's streaming synthesis API (different endpoint) and is out of
127+
// scope until we see demand.
128+
//
129+
// The `original` byte slice is intentionally ignored — the DashScope wire format differs
130+
// enough from the OpenAI request that we always re-marshal from the parsed struct rather
131+
// than patching the original body. Same reason forceBodyMutation is ignored: the response is
132+
// always a body replacement, never a passthrough.
133+
func (o *openAIToDashScopeSpeechTranslator) RequestBody(_ []byte, req *openai.SpeechRequest, _ bool) (
129134
newHeaders []internalapi.Header, newBody []byte, err error,
130135
) {
131136
if req == nil {
@@ -134,7 +139,7 @@ func (o *openAIToDashScopeSpeechTranslator) RequestBody(original []byte, req *op
134139

135140
model := req.Model
136141
if o.modelNameOverride != "" {
137-
model = string(o.modelNameOverride)
142+
model = o.modelNameOverride
138143
}
139144
o.requestModel = model
140145

@@ -154,7 +159,6 @@ func (o *openAIToDashScopeSpeechTranslator) RequestBody(original []byte, req *op
154159
{pathHeaderName, o.path},
155160
{contentLengthHeaderName, strconv.Itoa(len(newBody))},
156161
}
157-
_ = forceBodyMutation // always a shape change → always mutate.
158162
return
159163
}
160164

@@ -186,7 +190,7 @@ func (o *openAIToDashScopeSpeechTranslator) ResponseBody(_ map[string]string, bo
186190
if envelope.Output.Audio.URL == "" {
187191
return nil, nil, tokenUsage, "", fmt.Errorf("dashscope speech: response missing output.audio.url; body=%s", truncate(raw, 512))
188192
}
189-
if err := validateDashScopeAudioURL(envelope.Output.Audio.URL); err != nil {
193+
if err = validateDashScopeAudioURL(envelope.Output.Audio.URL); err != nil {
190194
return nil, nil, tokenUsage, "", err
191195
}
192196

internal/translator/openai_speech_dashscope_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func TestSpeechOpenAIToDashScope_ResponseBody(t *testing.T) {
100100
hm, body, _, respModel, err := tr.ResponseBody(nil, strings.NewReader(envelope), true, nil)
101101
require.NoError(t, err)
102102
require.Equal(t, audioPayload, body)
103-
require.Equal(t, "qwen3-tts-flash", string(respModel))
103+
require.Equal(t, "qwen3-tts-flash", respModel)
104104
require.Equal(t, "https://dashscope-intl.aliyuncs.com/audio/abc.wav", fetchedURL)
105105

106106
// content-length must match downloaded audio byte length.
@@ -184,7 +184,7 @@ func TestSpeechOpenAIToDashScope_ResponseBody(t *testing.T) {
184184
// DashScope actually returns plain-http URLs in the signed envelope, so http on an
185185
// allowed host must be accepted (host allowlist is the real defence).
186186
t.Run("accepts http on aliyuncs.com host", func(t *testing.T) {
187-
dashScopeAudioFetcher = func(_ context.Context, url string) ([]byte, error) {
187+
dashScopeAudioFetcher = func(_ context.Context, _ string) ([]byte, error) {
188188
return []byte("audio"), nil
189189
}
190190
tr := NewSpeechOpenAIToDashScopeTranslator("")

0 commit comments

Comments
 (0)