package clients import ( "context" "fmt" "math/rand" "strings" "time" ) type SimulationClient struct{} const ( defaultSimulationTextMinDuration = 800 * time.Millisecond defaultSimulationTextMaxDuration = 2400 * time.Millisecond defaultSimulationImageMinDuration = 10 * time.Second defaultSimulationImageMaxDuration = 30 * time.Second defaultSimulationVideoMinDuration = 2 * time.Minute defaultSimulationVideoMaxDuration = 3 * time.Minute maxSimulationDuration = 10 * time.Minute ) func (c SimulationClient) Run(ctx context.Context, request Request) (Response, error) { profile := simulationProfile(request) responseStartedAt := time.Now() duration := simulationDuration(request) if duration > 0 { timer := time.NewTimer(duration) select { case <-ctx.Done(): timer.Stop() return Response{}, ctx.Err() case <-timer.C: } } responseFinishedAt := time.Now() if profile == "retryable_failure" { return Response{}, &ClientError{ Code: "server_error", Message: "simulated retryable failure", RequestID: "simulated-request", ResponseStartedAt: responseStartedAt, ResponseFinishedAt: responseFinishedAt, ResponseDurationMS: responseDurationMS(responseStartedAt, responseFinishedAt), Retryable: true, } } if profile == "fatal_failure" || profile == "non_retryable_failure" { return Response{}, &ClientError{ Code: "bad_request", Message: "simulated non-retryable failure", RequestID: "simulated-request", ResponseStartedAt: responseStartedAt, ResponseFinishedAt: responseFinishedAt, ResponseDurationMS: responseDurationMS(responseStartedAt, responseFinishedAt), Retryable: false, } } result := simulatedResult(request) return Response{ Result: result, RequestID: requestIDFromResult(result), Usage: simulatedUsage(request), Progress: simulatedProgress(request), ResponseStartedAt: responseStartedAt, ResponseFinishedAt: responseFinishedAt, ResponseDurationMS: responseDurationMS(responseStartedAt, responseFinishedAt), }, nil } func simulationProfile(request Request) string { if value := stringValue(request.Candidate.Credentials, "simulationFailure"); value != "" { return value } if value := stringValue(request.Candidate.PlatformConfig, "simulationFailure"); value != "" { return value } if value := stringValue(request.Body, "simulationProfile"); value != "" { return value } if value := stringValue(request.Body, "testProfile"); value != "" { return value } return "success" } func simulatedResult(request Request) map[string]any { switch request.Kind { case "chat.completions": return map[string]any{ "id": "chatcmpl-simulated", "object": "chat.completion", "created": nowUnix(), "model": request.Model, "choices": []any{map[string]any{ "index": 0, "finish_reason": "stop", "message": map[string]any{ "role": "assistant", "content": fmt.Sprintf("simulation response from %s", request.Candidate.Provider), }, }}, "usage": map[string]any{"prompt_tokens": 12, "completion_tokens": 8, "total_tokens": 20}, } case "responses": return map[string]any{ "id": "resp-simulated", "object": "response", "created_at": nowUnix(), "model": request.Model, "output_text": fmt.Sprintf("simulation response from %s", request.Candidate.Provider), "usage": map[string]any{"input_tokens": 12, "output_tokens": 8, "total_tokens": 20}, } case "images.edits": return map[string]any{ "id": "img-edit-simulated", "created": nowUnix(), "model": request.Model, "data": simulatedImageData(request, "/static/simulation/image-edit.svg", "simulation image edit"), } case "images.generations": return map[string]any{ "id": "img-simulated", "created": nowUnix(), "model": request.Model, "data": simulatedImageData(request, "/static/simulation/image.svg", "simulation image"), } case "videos.generations": return map[string]any{ "id": "video-simulated", "created": nowUnix(), "model": request.Model, "data": simulatedVideoData(request), } default: modelType := strings.ToLower(request.ModelType) kind := strings.ToLower(request.Kind) if strings.Contains(modelType, "video") || strings.Contains(kind, "video") { return map[string]any{ "id": "video-simulated", "created": nowUnix(), "model": request.Model, "data": simulatedVideoData(request), } } return map[string]any{ "id": "img-simulated", "created": nowUnix(), "model": request.Model, "data": simulatedImageData(request, "/static/simulation/image.svg", "simulation image"), } } } func simulatedImageData(request Request, url string, fallbackPrompt string) []any { count := simulatedOutputCount(request.Body) items := make([]any, 0, count) for index := 0; index < count; index += 1 { items = append(items, map[string]any{ "url": url, "assetSource": "simulation", "index": index, "revised_prompt": firstNonEmptyPrompt(request.Body, fallbackPrompt), }) } return items } func simulatedVideoData(request Request) []any { count := simulatedOutputCount(request.Body) items := make([]any, 0, count) for index := 0; index < count; index += 1 { items = append(items, map[string]any{ "url": "/static/simulation/video.mp4", "video_url": "/static/simulation/video.mp4", "poster": "/static/simulation/video-poster.svg", "duration": simulatedVideoDurationSeconds(request), "assetSource": "simulation", "index": index, "revised_prompt": firstNonEmptyPrompt(request.Body, "simulation video"), }) } return items } func simulatedUsage(request Request) Usage { if request.ModelType == "chat" || request.Kind == "responses" { return Usage{InputTokens: 12, OutputTokens: 8, TotalTokens: 20} } return Usage{} } func simulatedProgress(request Request) []Progress { provider := request.Candidate.Provider if provider == "" { provider = "simulation" } return []Progress{ {Phase: "normalizing", Progress: 0.2, Message: "request normalized", Payload: map[string]any{"provider": provider}}, {Phase: "submitting", Progress: 0.55, Message: "simulation client submitted", Payload: map[string]any{"clientId": request.Candidate.ClientID}}, {Phase: "fetching_result", Progress: 0.85, Message: "simulation result ready", Payload: map[string]any{"kind": request.Kind}}, } } func simulationDuration(request Request) time.Duration { if fixedMS := simulationDurationMS(request, "simulationDurationMs", "testDurationMs"); fixedMS >= 0 { return clampSimulationDuration(time.Duration(fixedMS) * time.Millisecond) } if fixedSeconds := simulationDurationSeconds(request, "simulationDurationSeconds", "testDurationSeconds"); fixedSeconds >= 0 { return clampSimulationDuration(time.Duration(fixedSeconds) * time.Second) } minDuration, maxDuration := defaultSimulationDurationRange(request) if minMS := simulationDurationMS(request, "simulationMinDurationMs", "simulationDurationMinMs", "testMinDurationMs", "testDurationMinMs"); minMS >= 0 { minDuration = time.Duration(minMS) * time.Millisecond } if maxMS := simulationDurationMS(request, "simulationMaxDurationMs", "simulationDurationMaxMs", "testMaxDurationMs", "testDurationMaxMs"); maxMS >= 0 { maxDuration = time.Duration(maxMS) * time.Millisecond } if minSeconds := simulationDurationSeconds(request, "simulationMinDurationSeconds", "simulationDurationMinSeconds", "testMinDurationSeconds", "testDurationMinSeconds"); minSeconds >= 0 { minDuration = time.Duration(minSeconds) * time.Second } if maxSeconds := simulationDurationSeconds(request, "simulationMaxDurationSeconds", "simulationDurationMaxSeconds", "testMaxDurationSeconds", "testDurationMaxSeconds"); maxSeconds >= 0 { maxDuration = time.Duration(maxSeconds) * time.Second } minDuration = clampSimulationDuration(minDuration) maxDuration = clampSimulationDuration(maxDuration) if maxDuration < minDuration { maxDuration = minDuration } spread := maxDuration - minDuration if spread <= 0 { return minDuration } return minDuration + time.Duration(rand.Int63n(int64(spread)+1)) } func defaultSimulationDurationRange(request Request) (time.Duration, time.Duration) { if simulationVideoRequest(request) { return defaultSimulationVideoMinDuration, defaultSimulationVideoMaxDuration } if simulationImageRequest(request) { return defaultSimulationImageMinDuration, defaultSimulationImageMaxDuration } return defaultSimulationTextMinDuration, defaultSimulationTextMaxDuration } func simulationVideoRequest(request Request) bool { kind := strings.ToLower(request.Kind) modelType := strings.ToLower(request.ModelType) return strings.Contains(kind, "video") || strings.Contains(modelType, "video") } func simulationImageRequest(request Request) bool { kind := strings.ToLower(request.Kind) modelType := strings.ToLower(request.ModelType) return strings.Contains(kind, "image") || strings.Contains(modelType, "image") } func simulationDurationSeconds(request Request, keys ...string) int { for _, source := range []map[string]any{request.Body, request.Candidate.PlatformConfig, request.Candidate.Credentials} { for _, key := range keys { value := intValue(source, key, -1) if value >= 0 { return value } } } return -1 } func simulationDurationMS(request Request, keys ...string) int { for _, source := range []map[string]any{request.Body, request.Candidate.PlatformConfig, request.Candidate.Credentials} { for _, key := range keys { value := intValue(source, key, -1) if value >= 0 { return value } } } return -1 } func clampSimulationDuration(duration time.Duration) time.Duration { if duration < 0 { return 0 } if duration > maxSimulationDuration { return maxSimulationDuration } return duration } func simulatedOutputCount(body map[string]any) int { count := intValue(body, "n", 0) if count <= 0 { count = intValue(body, "count", 0) } if count <= 0 { return 1 } if count > 20 { return 20 } return count } func simulatedVideoDurationSeconds(request Request) int { for _, key := range []string{"duration", "duration_seconds", "durationSeconds"} { if value := intValue(request.Body, key, 0); value > 0 { return value } } return 5 } func firstNonEmptyPrompt(body map[string]any, fallback string) string { for _, key := range []string{"prompt", "input"} { if value := strings.TrimSpace(stringValue(body, key)); value != "" { return value } } return fallback }