Translate LLM backend capacity failures
This commit is contained in:
@@ -429,6 +429,89 @@ func TestPromptKitClientProviderFailureIncludesContextAndRedactsBearerToken(t *t
|
||||
}
|
||||
}
|
||||
|
||||
func TestPromptKitClientTranslatesBackendCapacityExhaustion(t *testing.T) {
|
||||
queueCapacity := 0
|
||||
fake := &fakePromptKitLLM{
|
||||
err: errors.New("provider failed with Bearer secret-token"),
|
||||
block: make(chan struct{}),
|
||||
}
|
||||
client, err := NewPromptKitClient(PromptKitClientConfig{
|
||||
Assets: newTestPromptKitAssets(t),
|
||||
EngineOptions: []promptkit.Option{
|
||||
promptkit.WithBackend(promptkit.Backend{
|
||||
ID: "limited-backend",
|
||||
Endpoint: "http://127.0.0.1:1/v1",
|
||||
ConcurrencyLimit: 1,
|
||||
QueueCapacity: &queueCapacity,
|
||||
}),
|
||||
promptkit.WithProfiles(promptkit.OpenAICompatibleProfile(promptkit.OpenAICompatibleProfileConfig{
|
||||
ID: "limited-profile",
|
||||
BackendID: "limited-backend",
|
||||
Model: "limited-model",
|
||||
})),
|
||||
promptkit.WithLLMClient(fake),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("NewPromptKitClient() error = %v, want nil", err)
|
||||
}
|
||||
defer func() {
|
||||
select {
|
||||
case <-fake.block:
|
||||
default:
|
||||
close(fake.block)
|
||||
}
|
||||
}()
|
||||
|
||||
request := contracts.StructuredCompletionRequest{
|
||||
PromptID: "adapter.direct-session",
|
||||
ProfileID: "limited-profile",
|
||||
Inputs: contracts.LLMInputSet{
|
||||
"transcript": contracts.NewLLMInputMaterial("transcript", "application/json", []byte(`{"source":true}`), "", ""),
|
||||
},
|
||||
Vars: map[string]any{"custom": "value"},
|
||||
}
|
||||
firstResult := make(chan error, 1)
|
||||
go func() {
|
||||
var out map[string]any
|
||||
_, callErr := client.CompleteStructured(context.Background(), request, &out)
|
||||
firstResult <- callErr
|
||||
}()
|
||||
waitForAtomicAtLeast(t, &fake.calls, 1)
|
||||
|
||||
var out map[string]any
|
||||
response, capacityErr := client.CompleteStructured(context.Background(), request, &out)
|
||||
if len(response.Content) != 0 {
|
||||
t.Fatalf("capacity response = %#v, want empty", response)
|
||||
}
|
||||
if !errors.Is(capacityErr, contracts.ErrLLMCapacityExceeded) {
|
||||
t.Fatalf("capacity error = %v, want ErrLLMCapacityExceeded", capacityErr)
|
||||
}
|
||||
if errors.Is(capacityErr, contracts.ErrInvalidStructuredOutput) {
|
||||
t.Fatalf("capacity error = %v, must not be invalid structured output", capacityErr)
|
||||
}
|
||||
if errors.Is(capacityErr, promptkit.ErrCapacityExceeded) {
|
||||
t.Fatalf("capacity error exposes PromptKit sentinel: %v", capacityErr)
|
||||
}
|
||||
if !strings.Contains(capacityErr.Error(), `run PromptKit prompt "adapter.direct-session"`) ||
|
||||
!strings.Contains(capacityErr.Error(), "backend capacity exceeded") {
|
||||
t.Fatalf("capacity error = %q, want prompt context and upstream diagnostic", capacityErr)
|
||||
}
|
||||
if calls := atomic.LoadInt32(&fake.calls); calls != 1 {
|
||||
t.Fatalf("provider calls after capacity rejection = %d, want 1", calls)
|
||||
}
|
||||
|
||||
close(fake.block)
|
||||
firstErr := <-firstResult
|
||||
if firstErr == nil || strings.Contains(firstErr.Error(), "secret-token") ||
|
||||
!strings.Contains(firstErr.Error(), "Bearer [REDACTED]") {
|
||||
t.Fatalf("admitted provider error = %v, want redacted diagnostic", firstErr)
|
||||
}
|
||||
if calls := atomic.LoadInt32(&fake.calls); calls != 1 {
|
||||
t.Fatalf("provider calls after release = %d, want no adapter retry", calls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPromptKitClientContextCancellationIsRespected(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
Reference in New Issue
Block a user