fix(terraform): send input_cost_per_reference_pixel on update when it changes to zero

The provider only sent the reference pixel rate when it was above zero, and
/model/update keeps any field it isn't sent. Clearing a positive rate in
Terraform therefore left the old rate billing while state recorded zero.
On update, send the rate whenever it changed, zero included
This commit is contained in:
Shreshth Kharbanda 2026-09-25 23:59:37 +00:00
parent 841a8abf8d
commit 648f127129
No known key found for this signature in database
3 changed files with 71 additions and 2 deletions

View file

@ -159,7 +159,7 @@ The following arguments are supported:
* `input_cost_per_pixel` - (Optional) float. Cost applied per input pixel for models that charge by image size.
* `input_cost_per_reference_pixel` - (Optional) float. Cost applied per billable pixel of the reference images sent with an image edit, for models that meter reference images separately. Azure AI FLUX.2 counts reference images in whole 1024x1024 megapixels.
* `input_cost_per_reference_pixel` - (Optional) float. Cost applied per billable pixel of the reference images sent with an image edit, for models that meter reference images separately. Azure AI FLUX.2 counts reference images in whole 1024x1024 megapixels. Changing it to 0 or removing it on an existing model sets the rate to 0, so reference images are then free.
* `output_cost_per_pixel` - (Optional) float. Cost applied per output pixel for image-generation models.

View file

@ -126,7 +126,8 @@ func createOrUpdateModel(d *schema.ResourceData, m interface{}, isUpdate bool) e
if inputCostPerPixel := d.Get("input_cost_per_pixel").(float64); inputCostPerPixel > 0 {
litellmParams["input_cost_per_pixel"] = inputCostPerPixel
}
if inputCostPerReferencePixel := d.Get("input_cost_per_reference_pixel").(float64); inputCostPerReferencePixel > 0 {
inputCostPerReferencePixel := d.Get("input_cost_per_reference_pixel").(float64)
if inputCostPerReferencePixel > 0 || (isUpdate && d.HasChange("input_cost_per_reference_pixel")) {
litellmParams["input_cost_per_reference_pixel"] = inputCostPerReferencePixel
}
if outputCostPerPixel := d.Get("output_cost_per_pixel").(float64); outputCostPerPixel > 0 {

View file

@ -242,3 +242,71 @@ func TestResourceLiteLLMModelUpdateSkipsPatchWhenDisplayNameUnchanged(t *testing
t.Fatalf("update failed: %v", err)
}
}
func TestResourceLiteLLMModelUpdateSendsReferencePixelRate(t *testing.T) {
cases := map[string]struct {
oldRate, newRate string
wantSent bool
wantRate float64
}{
"rate cleared to zero is sent": {oldRate: "2e-07", newRate: "0", wantSent: true, wantRate: 0},
"unchanged rate is sent": {oldRate: "2e-07", newRate: "2e-07", wantSent: true, wantRate: 2e-07},
"never set rate is omitted": {oldRate: "", newRate: "0", wantSent: false},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
var updateParams map[string]interface{}
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost && r.URL.Path == "/model/update" {
var payload map[string]interface{}
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
t.Errorf("failed to decode update payload: %v", err)
}
updateParams = payload["litellm_params"].(map[string]interface{})
w.Write([]byte(modelInfoBody("")))
return
}
w.Write([]byte(modelInfoDataEnvelope("")))
}))
defer srv.Close()
res := resourceLiteLLMModel()
attrs := map[string]string{
"model_name": "sonnet-4-5-anthropic",
"custom_llm_provider": "anthropic",
"base_model": "claude-sonnet-4-5",
}
if tc.oldRate != "" {
attrs["input_cost_per_reference_pixel"] = tc.oldRate
}
state := &terraform.InstanceState{ID: "model-123", Attributes: attrs}
config := map[string]interface{}{
"model_name": "sonnet-4-5-anthropic",
"custom_llm_provider": "anthropic",
"base_model": "claude-sonnet-4-5",
}
if tc.newRate != "0" {
config["input_cost_per_reference_pixel"] = tc.newRate
}
diff, err := res.Diff(context.Background(), state, &terraform.ResourceConfig{Config: config}, nil)
if err != nil {
t.Fatalf("diff failed: %v", err)
}
d, err := schema.InternalMap(res.Schema).Data(state, diff)
if err != nil {
t.Fatalf("data failed: %v", err)
}
if err := resourceLiteLLMModelUpdate(d, NewClient(srv.URL, "test-key", true)); err != nil {
t.Fatalf("update failed: %v", err)
}
rate, sent := updateParams["input_cost_per_reference_pixel"]
if sent != tc.wantSent {
t.Fatalf("expected input_cost_per_reference_pixel sent=%v, got %v (%v)", tc.wantSent, sent, rate)
}
if sent && rate != tc.wantRate {
t.Errorf("expected input_cost_per_reference_pixel %v, got %v", tc.wantRate, rate)
}
})
}
}