0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-12 05:02:14 +08:00
discourse/plugins/discourse-ai/spec/models/llm_model_spec.rb
Sam 6fc5673598
FEATURE: add cost limits to LLM quotas (#41277)
Track estimated request costs in AI audit logs and usage rollups so
quota
checks and usage reports can use the stored cost when available.

Add max cost quota fields to the admin UI, serializers, validations,
and staff logs.
2026-06-30 15:59:24 +10:00

111 lines
3.1 KiB
Ruby
Vendored

# frozen_string_literal: true
RSpec.describe LlmModel do
before { enable_current_plugin }
describe "api_key" do
fab!(:llm_model, :seeded_model)
before { ENV["DISCOURSE_AI_SEEDED_LLM_API_KEY_2"] = "blabla" }
it "should use environment variable over database value if seeded LLM" do
expect(llm_model.api_key).to eq("blabla")
end
end
describe "#credit_system_enabled?" do
fab!(:seeded_model)
fab!(:regular_model, :llm_model)
it "returns false for non-seeded models" do
expect(regular_model.credit_system_enabled?).to be false
end
it "returns false for seeded models without credit allocation" do
expect(seeded_model.credit_system_enabled?).to be false
end
it "returns true for seeded models with credit allocation" do
Fabricate(:llm_credit_allocation, llm_model: seeded_model)
expect(seeded_model.credit_system_enabled?).to be true
end
end
describe "AWS Bedrock provider validation" do
fab!(:bedrock_model, :bedrock_model)
it "requires either access_key_id or role_arn" do
# Should fail with neither
bedrock_model.provider_params = { region: "us-east-1" }
expect(bedrock_model.valid?).to be false
expect(bedrock_model.errors[:base]).to include(
I18n.t("discourse_ai.llm_models.bedrock_missing_auth"),
)
end
it "is valid with access_key_id only" do
bedrock_model.provider_params = { region: "us-east-1", access_key_id: "test_key" }
expect(bedrock_model.valid?).to be true
end
it "is valid with role_arn only" do
bedrock_model.provider_params = {
region: "us-east-1",
role_arn: "arn:aws:iam::123:role/test",
}
expect(bedrock_model.valid?).to be true
end
end
describe "#estimated_cost_for_tokens" do
it "calculates request, response, cache read, and cache write cost" do
model =
Fabricate.build(
:llm_model,
input_cost: 3.0,
output_cost: 15.0,
cached_input_cost: 0.3,
cache_write_cost: 3.75,
)
cost =
model.estimated_cost_for_tokens(
request_tokens: 1_000_000,
response_tokens: 100_000,
cache_read_tokens: 10_000,
cache_write_tokens: 1_000,
)
expect(cost).to eq(BigDecimal("4.50675"))
end
it "returns nil when no costs are configured" do
model =
Fabricate.build(
:llm_model,
input_cost: nil,
output_cost: nil,
cached_input_cost: nil,
cache_write_cost: 0,
)
expect(
model.estimated_cost_for_tokens(
request_tokens: 1_000_000,
response_tokens: 100_000,
cache_read_tokens: 10_000,
cache_write_tokens: 1_000,
),
).to be_nil
end
end
describe "allowed_attachment_types" do
it "normalizes markdown attachments to md" do
model = Fabricate.build(:llm_model)
model.allowed_attachment_types = %w[pdf markdown md htm text]
expect(model.allowed_attachment_types).to eq(%w[pdf md html txt])
end
end
end