@@ -2076,6 +2076,35 @@ func newMockServer(ctx context.Context, t *testing.T, files archiveFileMap, requ
20762076 defer r .Body .Close ()
20772077 require .NoError (t , err )
20782078
2079+ // Validate request body based on endpoint.
2080+ var validationErr error
2081+ if strings .Contains (r .URL .Path , "/chat/completions" ) {
2082+ validationErr = validateOpenAIChatCompletionRequest (body )
2083+ } else if strings .Contains (r .URL .Path , "/responses" ) {
2084+ validationErr = validateOpenAIResponsesRequest (body )
2085+ } else if strings .Contains (r .URL .Path , "/messages" ) {
2086+ validationErr = validateAnthropicMessagesRequest (body )
2087+ }
2088+
2089+ // If validation failed, return error response
2090+ if validationErr != nil {
2091+ // Return HTTP error response
2092+ w .Header ().Set ("Content-Type" , "application/json" )
2093+ w .WriteHeader (http .StatusBadRequest )
2094+ errResp := map [string ]any {
2095+ "error" : map [string ]any {
2096+ "message" : fmt .Sprintf ("Request #%d validation failed: %v" , ms .callCount .Load (), validationErr ),
2097+ "type" : "invalid_request_error" ,
2098+ },
2099+ }
2100+ json .NewEncoder (w ).Encode (errResp )
2101+
2102+ // Mark test as failed with detailed message
2103+ t .Errorf ("Request #%d validation failed: %v\n \n Request body:\n %s" ,
2104+ ms .callCount .Load (), validationErr , string (body ))
2105+ return
2106+ }
2107+
20792108 type msg struct {
20802109 Stream bool `json:"stream"`
20812110 }
@@ -2135,6 +2164,72 @@ func newMockServer(ctx context.Context, t *testing.T, files archiveFileMap, requ
21352164 return ms
21362165}
21372166
2167+ // validateOpenAIChatCompletionRequest validates that an OpenAI chat completion request
2168+ // has all required fields. Returns an error if validation fails.
2169+ func validateOpenAIChatCompletionRequest (body []byte ) error {
2170+ var req openai.ChatCompletionNewParams
2171+ if err := json .Unmarshal (body , & req ); err != nil {
2172+ return fmt .Errorf ("request should unmarshal into ChatCompletionNewParams: %w" , err )
2173+ }
2174+
2175+ // Collect all validation errors
2176+ var errs []string
2177+ if req .Model == "" {
2178+ errs = append (errs , "model field is required but empty" )
2179+ }
2180+ if len (req .Messages ) == 0 {
2181+ errs = append (errs , "messages field is required but empty" )
2182+ }
2183+
2184+ if len (errs ) > 0 {
2185+ return fmt .Errorf ("validation failed: %s" , strings .Join (errs , "; " ))
2186+ }
2187+ return nil
2188+ }
2189+
2190+ // validateOpenAIResponsesRequest validates that an OpenAI responses request
2191+ // has all required fields. Returns an error if validation fails.
2192+ func validateOpenAIResponsesRequest (body []byte ) error {
2193+ var reqBody map [string ]any
2194+ if err := json .Unmarshal (body , & reqBody ); err != nil {
2195+ return fmt .Errorf ("request should be valid JSON: %w" , err )
2196+ }
2197+
2198+ // Verify required fields for OpenAI responses
2199+ // Note: Using map here since there's no specific SDK type for responses endpoint
2200+ model , ok := reqBody ["model" ]
2201+ if ! ok || model == "" {
2202+ return fmt .Errorf ("model field is required but missing or empty" )
2203+ }
2204+ return nil
2205+ }
2206+
2207+ // validateAnthropicMessagesRequest validates that an Anthropic messages request
2208+ // has all required fields. Returns an error if validation fails.
2209+ func validateAnthropicMessagesRequest (body []byte ) error {
2210+ var req anthropic.MessageNewParams
2211+ if err := json .Unmarshal (body , & req ); err != nil {
2212+ return fmt .Errorf ("request should unmarshal into MessageNewParams: %w" , err )
2213+ }
2214+
2215+ // Collect all validation errors
2216+ var errs []string
2217+ if req .Model == "" {
2218+ errs = append (errs , "model field is required but empty" )
2219+ }
2220+ if len (req .Messages ) == 0 {
2221+ errs = append (errs , "messages field is required but empty" )
2222+ }
2223+ if req .MaxTokens == 0 {
2224+ errs = append (errs , "max_tokens field is required but zero" )
2225+ }
2226+
2227+ if len (errs ) > 0 {
2228+ return fmt .Errorf ("validation failed: %s" , strings .Join (errs , "; " ))
2229+ }
2230+ return nil
2231+ }
2232+
21382233const mockToolName = "coder_list_workspaces"
21392234
21402235// callAccumulator tracks all tool invocations by name and each instance's arguments.
0 commit comments