mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
Merge 92688af811 into dab2deb5ed
This commit is contained in:
commit
b77d33a907
3 changed files with 77 additions and 13 deletions
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
)
|
||||
|
||||
|
|
@ -29,7 +30,10 @@ func resourceLiteLLMVectorStoreCreate(d *schema.ResourceData, m interface{}) err
|
|||
paramsMap[k] = v
|
||||
}
|
||||
|
||||
vectorStoreID := uuid.New().String()
|
||||
|
||||
vectorStoreRequest := VectorStoreRequest{
|
||||
VectorStoreID: vectorStoreID,
|
||||
CustomLLMProvider: customLLMProvider,
|
||||
VectorStoreName: vectorStoreName,
|
||||
VectorStoreDescription: vectorStoreDescription,
|
||||
|
|
@ -49,9 +53,7 @@ func resourceLiteLLMVectorStoreCreate(d *schema.ResourceData, m interface{}) err
|
|||
return fmt.Errorf("failed to create vector store: %w", err)
|
||||
}
|
||||
|
||||
// Set the resource ID to the vector store name for now
|
||||
// We'll update this after reading the response to get the actual ID
|
||||
d.SetId(vectorStoreName)
|
||||
d.SetId(vectorStoreID)
|
||||
|
||||
return resourceLiteLLMVectorStoreRead(d, m)
|
||||
}
|
||||
|
|
@ -76,8 +78,10 @@ func resourceLiteLLMVectorStoreRead(d *schema.ResourceData, m interface{}) error
|
|||
return nil
|
||||
}
|
||||
|
||||
var vectorStoreResp VectorStoreResponse
|
||||
err = handleVectorStoreAPIResponse(resp, &vectorStoreResp, client)
|
||||
var infoResp struct {
|
||||
VectorStore VectorStoreResponse `json:"vector_store"`
|
||||
}
|
||||
err = handleVectorStoreAPIResponse(resp, &infoResp, client)
|
||||
if err != nil {
|
||||
if err.Error() == "vector_store_not_found" {
|
||||
d.SetId("")
|
||||
|
|
@ -85,6 +89,7 @@ func resourceLiteLLMVectorStoreRead(d *schema.ResourceData, m interface{}) error
|
|||
}
|
||||
return fmt.Errorf("failed to read vector store: %w", err)
|
||||
}
|
||||
vectorStoreResp := infoResp.VectorStore
|
||||
|
||||
// Update the resource ID to the actual vector store ID from the response
|
||||
if vectorStoreResp.VectorStoreID != "" {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ func TestVectorStoreReadDoesNotPersistServerLitellmParams(t *testing.T) {
|
|||
"api_base": "https://upstream.example.com",
|
||||
},
|
||||
}
|
||||
body, _ := json.Marshal(resp)
|
||||
body, _ := json.Marshal(map[string]interface{}{"vector_store": resp})
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
|
@ -53,3 +53,61 @@ func TestVectorStoreReadDoesNotPersistServerLitellmParams(t *testing.T) {
|
|||
t.Fatalf("read did not populate non-sensitive fields")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVectorStoreCreateSendsGeneratedIDAndUsesItAsResourceID(t *testing.T) {
|
||||
var createBody map[string]interface{}
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if r.URL.Path == "/vector_store/new" {
|
||||
json.NewDecoder(r.Body).Decode(&createBody)
|
||||
id, _ := createBody["vector_store_id"].(string)
|
||||
if id == "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(`{"detail":"vector_store_id and custom_llm_provider are required"}`))
|
||||
return
|
||||
}
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"status": "success",
|
||||
"vector_store": VectorStoreResponse{VectorStoreID: id, VectorStoreName: "kb", CustomLLMProvider: "openai"},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var info VectorStoreInfoRequest
|
||||
json.NewDecoder(r.Body).Decode(&info)
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"vector_store": VectorStoreResponse{
|
||||
VectorStoreID: info.VectorStoreID,
|
||||
VectorStoreName: "kb",
|
||||
CustomLLMProvider: "openai",
|
||||
CreatedAt: "2026-01-01T00:00:00Z",
|
||||
},
|
||||
})
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
d := schema.TestResourceDataRaw(t, resourceLiteLLMVectorStore().Schema, map[string]interface{}{
|
||||
"vector_store_name": "kb",
|
||||
"custom_llm_provider": "openai",
|
||||
})
|
||||
|
||||
if err := resourceLiteLLMVectorStoreCreate(d, NewClient(srv.URL, "test-key", true)); err != nil {
|
||||
t.Fatalf("create failed: %v", err)
|
||||
}
|
||||
|
||||
sentID, _ := createBody["vector_store_id"].(string)
|
||||
if sentID == "" {
|
||||
t.Fatal("create payload omitted vector_store_id, which the proxy rejects")
|
||||
}
|
||||
if d.Id() != sentID {
|
||||
t.Errorf("resource id = %q, want the created store id %q", d.Id(), sentID)
|
||||
}
|
||||
if d.Get("vector_store_id").(string) != sentID {
|
||||
t.Errorf("vector_store_id = %q, want %q", d.Get("vector_store_id").(string), sentID)
|
||||
}
|
||||
if d.Get("created_at").(string) != "2026-01-01T00:00:00Z" {
|
||||
t.Errorf("create did not refresh computed fields from the API: %v", d.Get("created_at"))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@ OpenAPI compliance tests for Google Interactions API.
|
|||
|
||||
Validates that our SDK requests/responses match the OpenAPI spec at:
|
||||
https://ai.google.dev/static/api/interactions.openapi.json
|
||||
Schema names verified against that spec on 2026-09-28.
|
||||
|
||||
Run with: pytest tests/unit/interactions/test_openapi_compliance.py -v
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from typing import Any, Dict
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
|
|
@ -60,12 +62,11 @@ class TestRequestCompliance:
|
|||
"""Tests that our request bodies match the OpenAPI spec."""
|
||||
|
||||
def test_create_model_interaction_request_schema(self, spec_dict):
|
||||
"""Verify CreateModelInteractionParams schema fields."""
|
||||
schema = spec_dict["components"]["schemas"]["CreateModelInteractionParams"]
|
||||
"""Verify ModelInteraction schema fields."""
|
||||
schema = spec_dict["components"]["schemas"]["ModelInteraction"]
|
||||
|
||||
# Required fields per spec
|
||||
assert "model" in schema["required"]
|
||||
assert "input" in schema["required"]
|
||||
assert "input" in schema["properties"]
|
||||
|
||||
# Check our supported optional fields exist in spec
|
||||
our_optional_fields = [
|
||||
|
|
@ -88,7 +89,7 @@ class TestRequestCompliance:
|
|||
|
||||
def test_input_types_match_spec(self, spec_dict):
|
||||
"""Verify input field supports string, Content, Content[], Turn[]."""
|
||||
schema = spec_dict["components"]["schemas"]["CreateModelInteractionParams"]
|
||||
schema = spec_dict["components"]["schemas"]["ModelInteraction"]
|
||||
input_schema = schema["properties"]["input"]
|
||||
|
||||
# The input property may be inline oneOf or a $ref to InteractionsInput
|
||||
|
|
@ -313,7 +314,7 @@ class TestEndpointCompliance:
|
|||
|
||||
get_path = None
|
||||
for path, methods in paths.items():
|
||||
if "{id}" in path and "interactions" in path and "get" in methods:
|
||||
if re.fullmatch(r".*/interactions/\{[^/{}]+\}", path) and "get" in methods:
|
||||
get_path = path
|
||||
break
|
||||
|
||||
|
|
@ -326,7 +327,7 @@ class TestEndpointCompliance:
|
|||
|
||||
delete_path = None
|
||||
for path, methods in paths.items():
|
||||
if "{id}" in path and "interactions" in path and "delete" in methods:
|
||||
if re.fullmatch(r".*/interactions/\{[^/{}]+\}", path) and "delete" in methods:
|
||||
delete_path = path
|
||||
break
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue