Ctrl K
ComunidadGuías…

internal/app/tier_fallback_integration_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
//go:build !nobundledharness

package app

import (
	"context"
	"encoding/json"
	"log/slog"
	"net/http"
	"net/http/httptest"
	"strings"
	"sync"
	"testing"

	"github.com/yeomyeonggeori/blueclaw/internal/llm"
)

func TestLowTierEscalatesToMediumThroughRealCapabilityTransport(t *testing.T) {
	requestedModels := []string{}
	var requestedModelsLock sync.Mutex
	server := httptest.NewServer(http.HandlerFunc(func(responseWriter http.ResponseWriter, request *http.Request) {
		if !strings.HasSuffix(request.URL.Path, "/llm/structured") {
			http.Error(responseWriter, "unexpected path "+request.URL.Path, http.StatusNotFound)
			return
		}
		var document map[string]any
		if errorValue := json.NewDecoder(request.Body).Decode(&document); errorValue != nil {
			http.Error(responseWriter, errorValue.Error(), http.StatusBadRequest)
			return
		}
		modelName, _ := document["model"].(string)
		requestedModelsLock.Lock()
		requestedModels = append(requestedModels, modelName)
		requestedModelsLock.Unlock()
		if modelName == "vendor/low" {
			http.Error(responseWriter, "provider returned error (502)", http.StatusBadGateway)
			return
		}
		json.NewEncoder(responseWriter).Encode(map[string]any{
			"provider": "example-gateway",
			"model":    modelName,
			"content":  `{"action":"reply","final":true}`,
		})
	}))
	defer server.Close()

	runtimeConfiguration := configuredModelTierRuntime("")
	runtimeConfiguration.Capabilities.Endpoint = server.URL

	providers, errorValue := resolveTaskTierLanguageModelProviders(runtimeConfiguration, slog.New(slog.DiscardHandler))
	if errorValue != nil {
		t.Fatal(errorValue)
	}
	response, errorValue := providers.Low.GenerateStructuredResponse(context.Background(), llm.StructuredResponseRequest{
		Messages: []llm.Message{{Role: "user", Content: "test"}},
		StructuredOutputSchema: llm.StructuredOutputSchema{
			Name:     "bluecollar_agent_turn_action",
			Document: `{"type":"object"}`,
		},
	})
	if errorValue != nil {
		t.Fatalf("expected the low tier to escalate to medium and succeed, got error: %v (models requested: %v)", errorValue, requestedModels)
	}
	if !response.UsedFallback {
		t.Fatalf("expected UsedFallback to be marked, got %+v (models requested: %v)", response, requestedModels)
	}
	if response.ModelTier != "medium" {
		t.Fatalf("expected the successful fallback response to report medium tier, got %+v", response)
	}
	requestedModelsLock.Lock()
	defer requestedModelsLock.Unlock()
	if len(requestedModels) < 2 || requestedModels[len(requestedModels)-1] != "vendor/medium" {
		t.Fatalf("expected a final vendor/medium request after vendor/low failures, got %v", requestedModels)
	}
}

func TestCappedHighTierReportsLowModelTier(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(responseWriter http.ResponseWriter, request *http.Request) {
		if !strings.HasSuffix(request.URL.Path, "/llm/structured") {
			http.Error(responseWriter, "unexpected path "+request.URL.Path, http.StatusNotFound)
			return
		}
		json.NewEncoder(responseWriter).Encode(map[string]any{
			"provider": "example-gateway",
			"model":    "vendor/low",
			"content":  `{"action":"reply","final":true}`,
		})
	}))
	defer server.Close()

	runtimeConfiguration := configuredModelTierRuntime("low")
	runtimeConfiguration.Capabilities.Endpoint = server.URL
	providers, errorValue := resolveTaskTierLanguageModelProviders(runtimeConfiguration, slog.New(slog.DiscardHandler))
	if errorValue != nil {
		t.Fatal(errorValue)
	}
	response, errorValue := providers.High.GenerateStructuredResponse(context.Background(), llm.StructuredResponseRequest{
		StructuredOutputSchema: llm.StructuredOutputSchema{Name: "bluecollar_agent_turn_action", Document: `{"type":"object"}`},
	})
	if errorValue != nil {
		t.Fatalf("expected capped high provider to succeed: %v", errorValue)
	}
	if response.ModelTier != "low" {
		t.Fatalf("expected capped high provider to report low tier, got %+v", response)
	}
}