fix: Address copilot review comments

This commit is contained in:
Kayvan Sylvan 2026-02-23 14:29:25 -08:00
parent 283a548e05
commit 103493206e
13 changed files with 49 additions and 15 deletions

View file

@ -173,7 +173,7 @@ fabric --youtube "https://youtube.com/watch?v=example" --model us.anthropic.clau
curl -s https://example.com/article | fabric --model gpt-4o --pattern summarize
# Create content from a prompt (Vertex AI)
fabric --model gemini-1.5-pro --pattern write_essay --stream
fabric --model gemini-1.5-pro --pattern write_essay
```
### Switching Between Backends
@ -327,10 +327,10 @@ Fabric configuration is stored in `~/.config/fabric/.env`. Manual editing is sup
```bash
# Example configuration
AZURE_AI_GATEWAY_BACKEND=bedrock
AZURE_AI_GATEWAY_GATEWAY_URL=https://gateway.company.com
AZURE_AI_GATEWAY_SUBSCRIPTION_KEY=your-key-here
AZURE_AI_GATEWAY_API_VERSION=2025-04-01-preview
AZUREAIGATEWAY_BACKEND=bedrock
AZUREAIGATEWAY_GATEWAY_URL=https://gateway.company.com
AZUREAIGATEWAY_SUBSCRIPTION_KEY=your-key-here
AZUREAIGATEWAY_API_VERSION=2025-04-01-preview
```
## Support

View file

@ -43,6 +43,7 @@
"azureaigateway_invalid_gateway_url": "ungültige Gateway-URL: %w",
"azureaigateway_no_valid_messages": "keine gültigen Nachrichten nach Filterung leerer Inhalte",
"azureaigateway_prepare_request_failed": "AzureAIGateway: %w",
"azureaigateway_response_too_large": "AzureAIGateway: Antwort zu groß (>%d Bytes)",
"azureaigateway_subscription_key_question": "Geben Sie Ihren Azure APIM-Abonnementschlüssel ein",
"azureaigateway_subscription_key_required": "Azure APIM-Abonnementschlüssel ist erforderlich",
"azureaigateway_unsupported_backend": "nicht unterstütztes Backend: %s (gültige Optionen: bedrock, azure-openai, vertex-ai)",

View file

@ -43,6 +43,7 @@
"azureaigateway_invalid_gateway_url": "invalid gateway URL: %w",
"azureaigateway_no_valid_messages": "no valid messages after filtering empty content",
"azureaigateway_prepare_request_failed": "AzureAIGateway: %w",
"azureaigateway_response_too_large": "AzureAIGateway: response too large (>%d bytes)",
"azureaigateway_subscription_key_question": "Enter your Azure APIM subscription key",
"azureaigateway_subscription_key_required": "azure APIM subscription key is required",
"azureaigateway_unsupported_backend": "unsupported backend: %s (valid options: bedrock, azure-openai, vertex-ai)",

View file

@ -43,6 +43,7 @@
"azureaigateway_invalid_gateway_url": "URL de gateway inválida: %w",
"azureaigateway_no_valid_messages": "sin mensajes válidos después de filtrar contenido vacío",
"azureaigateway_prepare_request_failed": "AzureAIGateway: %w",
"azureaigateway_response_too_large": "AzureAIGateway: respuesta demasiado grande (>%d bytes)",
"azureaigateway_subscription_key_question": "Ingrese su clave de suscripción de Azure APIM",
"azureaigateway_subscription_key_required": "se requiere la clave de suscripción de Azure APIM",
"azureaigateway_unsupported_backend": "backend no soportado: %s (opciones válidas: bedrock, azure-openai, vertex-ai)",

View file

@ -43,6 +43,7 @@
"azureaigateway_invalid_gateway_url": "آدرس Gateway نامعتبر: %w",
"azureaigateway_no_valid_messages": "هیچ پیام معتبری پس از فیلتر کردن محتوای خالی وجود ندارد",
"azureaigateway_prepare_request_failed": "AzureAIGateway: %w",
"azureaigateway_response_too_large": "AzureAIGateway: پاسخ خیلی بزرگ است (>%d بایت)",
"azureaigateway_subscription_key_question": "کلید اشتراک Azure APIM خود را وارد کنید",
"azureaigateway_subscription_key_required": "کلید اشتراک Azure APIM الزامی است",
"azureaigateway_unsupported_backend": "بک‌اند پشتیبانی نشده: %s (گزینه‌های معتبر: bedrock، azure-openai، vertex-ai)",

View file

@ -43,6 +43,7 @@
"azureaigateway_invalid_gateway_url": "URL du gateway invalide : %w",
"azureaigateway_no_valid_messages": "aucun message valide après filtrage du contenu vide",
"azureaigateway_prepare_request_failed": "AzureAIGateway : %w",
"azureaigateway_response_too_large": "AzureAIGateway : réponse trop volumineuse (>%d octets)",
"azureaigateway_subscription_key_question": "Entrez votre clé d'abonnement Azure APIM",
"azureaigateway_subscription_key_required": "la clé d'abonnement Azure APIM est requise",
"azureaigateway_unsupported_backend": "backend non pris en charge : %s (options valides : bedrock, azure-openai, vertex-ai)",

View file

@ -43,6 +43,7 @@
"azureaigateway_invalid_gateway_url": "URL del gateway non valido: %w",
"azureaigateway_no_valid_messages": "nessun messaggio valido dopo il filtraggio del contenuto vuoto",
"azureaigateway_prepare_request_failed": "AzureAIGateway: %w",
"azureaigateway_response_too_large": "AzureAIGateway: risposta troppo grande (>%d byte)",
"azureaigateway_subscription_key_question": "Inserire la propria chiave di sottoscrizione Azure APIM",
"azureaigateway_subscription_key_required": "la chiave di sottoscrizione Azure APIM è obbligatoria",
"azureaigateway_unsupported_backend": "backend non supportato: %s (opzioni valide: bedrock, azure-openai, vertex-ai)",

View file

@ -43,6 +43,7 @@
"azureaigateway_invalid_gateway_url": "無効なゲートウェイURL: %w",
"azureaigateway_no_valid_messages": "空のコンテンツをフィルタリングした後、有効なメッセージがありません",
"azureaigateway_prepare_request_failed": "AzureAIGateway: %w",
"azureaigateway_response_too_large": "AzureAIGateway: レスポンスが大きすぎます (>%dバイト)",
"azureaigateway_subscription_key_question": "Azure APIMサブスクリプションキーを入力してください",
"azureaigateway_subscription_key_required": "Azure APIMサブスクリプションキーは必須です",
"azureaigateway_unsupported_backend": "サポートされていないバックエンド: %s有効なオプション: bedrock、azure-openai、vertex-ai",

View file

@ -43,6 +43,7 @@
"azureaigateway_invalid_gateway_url": "URL do gateway inválida: %w",
"azureaigateway_no_valid_messages": "sem mensagens válidas após filtrar conteúdo vazio",
"azureaigateway_prepare_request_failed": "AzureAIGateway: %w",
"azureaigateway_response_too_large": "AzureAIGateway: resposta muito grande (>%d bytes)",
"azureaigateway_subscription_key_question": "Insira sua chave de assinatura do Azure APIM",
"azureaigateway_subscription_key_required": "a chave de assinatura do Azure APIM é obrigatória",
"azureaigateway_unsupported_backend": "backend não suportado: %s (opções válidas: bedrock, azure-openai, vertex-ai)",

View file

@ -43,6 +43,7 @@
"azureaigateway_invalid_gateway_url": "URL do gateway inválido: %w",
"azureaigateway_no_valid_messages": "sem mensagens válidas após filtragem de conteúdo vazio",
"azureaigateway_prepare_request_failed": "AzureAIGateway: %w",
"azureaigateway_response_too_large": "AzureAIGateway: resposta demasiado grande (>%d bytes)",
"azureaigateway_subscription_key_question": "Introduza a sua chave de subscrição do Azure APIM",
"azureaigateway_subscription_key_required": "a chave de subscrição do Azure APIM é obrigatória",
"azureaigateway_unsupported_backend": "backend não suportado: %s (opções válidas: bedrock, azure-openai, vertex-ai)",

View file

@ -43,6 +43,7 @@
"azureaigateway_invalid_gateway_url": "无效的网关 URL: %w",
"azureaigateway_no_valid_messages": "过滤空内容后没有有效消息",
"azureaigateway_prepare_request_failed": "AzureAIGateway: %w",
"azureaigateway_response_too_large": "AzureAIGateway: 响应太大 (>%d字节)",
"azureaigateway_subscription_key_question": "输入您的 Azure APIM 订阅密钥",
"azureaigateway_subscription_key_required": "Azure APIM 订阅密钥是必需的",
"azureaigateway_unsupported_backend": "不支持的后端: %s有效选项: bedrock、azure-openai、vertex-ai",

View file

@ -169,12 +169,16 @@ func (c *Client) Send(ctx context.Context, msgs []*chat.ChatCompletionMessage, o
}
defer resp.Body.Close()
// Limit response body size to 10MB to prevent memory exhaustion
limitedBody := io.LimitReader(resp.Body, 10*1024*1024)
// Read up to 10MB+1 byte to detect truncation
const maxResponseSize = 10 * 1024 * 1024
limitedBody := io.LimitReader(resp.Body, maxResponseSize+1)
respBody, err := io.ReadAll(limitedBody)
if err != nil {
return "", fmt.Errorf(i18n.T("azureaigateway_failed_read_response"), err)
}
if len(respBody) > maxResponseSize {
return "", fmt.Errorf(i18n.T("azureaigateway_response_too_large"), maxResponseSize)
}
debuglog.Debug(debuglog.Detailed, "AzureAIGateway response status: %d\n", resp.StatusCode)

View file

@ -3,16 +3,29 @@ package azureaigateway
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"github.com/danielmiessler/fabric/internal/chat"
"github.com/danielmiessler/fabric/internal/domain"
"github.com/danielmiessler/fabric/internal/i18n"
)
// TestMain pins the locale to English so that i18n.T() assertions
// are deterministic regardless of the CI machine's system locale.
func TestMain(m *testing.M) {
if _, err := i18n.Init("en"); err != nil {
fmt.Fprintf(os.Stderr, "failed to init i18n: %v\n", err)
os.Exit(1)
}
os.Exit(m.Run())
}
// --- Bedrock Backend Tests ---
func TestBedrockBuildEndpoint(t *testing.T) {
@ -732,13 +745,20 @@ func TestSendModelNotFoundError(t *testing.T) {
}
}
// failingRoundTripper always returns an error, simulating a network failure.
type failingRoundTripper struct{}
func (f *failingRoundTripper) RoundTrip(*http.Request) (*http.Response, error) {
return nil, fmt.Errorf("connection refused")
}
func TestSendNetworkError(t *testing.T) {
// ISC-C17: Test unreachable gateway URL → connection error
// ISC-C17: Test network failure → connection error (deterministic, no real DNS)
c := NewClient()
c.GatewayURL.Value = "https://non-existent-gateway-12345.invalid"
c.GatewayURL.Value = "https://gateway.example.com"
c.SubscriptionKey.Value = "test-key"
c.BackendType.Value = "bedrock"
c.httpClient = &http.Client{Timeout: gatewayTimeout}
c.httpClient = &http.Client{Transport: &failingRoundTripper{}}
c.backend = NewBedrockBackend("test-key")
msgs := []*chat.ChatCompletionMessage{
@ -752,7 +772,7 @@ func TestSendNetworkError(t *testing.T) {
_, err := c.Send(context.Background(), msgs, opts)
if err == nil {
t.Fatal("Send() expected error for unreachable gateway")
t.Fatal("Send() expected error for network failure")
}
if !strings.Contains(err.Error(), "HTTP request failed") {
t.Errorf("error should mention HTTP request failure: %v", err)
@ -903,11 +923,11 @@ func TestSendStreamFallback(t *testing.T) {
// --- ISC-C18: API Version Compatibility Test ---
func TestAzureOpenAIAPIVersionCompatibility(t *testing.T) {
// ISC-C18: Azure OpenAI API version 2025-04-01-preview compatibility with Azure APIM Gateway
// ISC-C18: Azure OpenAI API version compatibility with Azure APIM Gateway
// Reference: https://learn.microsoft.com/en-us/azure/ai-services/openai/api-version-deprecation
// This test verifies that the API version in the endpoint is compatible with Azure APIM Gateway.
// The version 2024-10-21 is currently used, which is compatible with APIM gateways.
// When updating to 2025-04-01-preview, ensure APIM gateway supports the new version.
// This test verifies that the default API version in the endpoint (currently 2025-04-01-preview)
// is explicitly set and is compatible with Azure APIM Gateway. When changing the default API
// version in the backend, ensure that APIM gateways are updated to support the new version.
b := NewAzureOpenAIBackend("key", "")
endpoint := b.BuildEndpoint("https://gw.example.com", "gpt-4")