Skip to main content
Version: 2.x

:::info Executable tutorial

This page is generated from a tested Jupyter notebook. Open it in Google Colab or view the source notebook.

:::

Write safe pricing expressions

Bursar's expression language supports minimum charges, caps, conditional pricing, and volume tiers without executing application code. This tutorial evaluates formulas with exact decimals and verifies the sandbox boundary.

Learning objectives​

After completing this tutorial, you can:

  • Evaluate arithmetic, conditional, tier, and rounding expressions
  • Supply usage measures as expression variables
  • Validate a formula before publishing configuration
  • Explain which syntax and operations the sandbox rejects

Prerequisites​

  • Read the pricing engine tutorial
  • Start the notebook server from samples/python/notebooks/

Evaluate the basic operators​

evaluate_expression(formula, variables) parses, validates, and evaluates a formula in exact Decimal arithmetic. Variables come from UsageMetrics.measures. Standard arithmetic precedence applies.

from decimal import Decimal

from bursar.expr import evaluate_expression, validate_expression, ExpressionError

# The rate card fallback, computed by hand: 2 * 5 + 3 * 15 = 55.
print("line rate:", evaluate_expression("input_tokens * 5 + output_tokens * 15", {"input_tokens": 2, "output_tokens": 3}))

# Parentheses: (2 + 3) * 2 = 10.
print("parens: ", evaluate_expression("(input_tokens + output_tokens) * 2", {"input_tokens": 2, "output_tokens": 3}))

# Division: 10 / 4 = 2.5, exact.
print("division:", evaluate_expression("input_tokens / 4", {"input_tokens": 10}))

Floors and caps: max() and min()​

max() enforces a minimum charge floor — a 50-credit floor means tiny completions still cost 50. min() caps a charge at a ceiling, the inverse guardrail.

# max(a, b, ...) returns the largest argument: the floor wins at 50.
print("floor:", evaluate_expression("max(50, input_tokens * 2)", {"input_tokens": 10}))
print("above floor:", evaluate_expression("max(50, input_tokens * 2)", {"input_tokens": 40}))

# min(a, b, ...) returns the smallest argument: the cap wins at 100.
print("cap:", evaluate_expression("min(100, input_tokens * 2)", {"input_tokens": 70}))
print("below cap:", evaluate_expression("min(100, input_tokens * 2)", {"input_tokens": 10}))

Conditionals: if()​

if(condition, then, else) is the language's branch. This example makes completions under 100 input tokens free and charges 1.5 credits for other completions. Conditions support comparisons and and/or; the if(...) spelling is rewritten internally to a safe function call.

print("under 100 tokens:", evaluate_expression("if(input_tokens < 100, 0, 1.5)", {"input_tokens": 50}))
print("over 100 tokens:", evaluate_expression("if(input_tokens < 100, 0, 1.5)", {"input_tokens": 150}))

# Conditions nest: free only when both measures are small.
print(
"nested:",
evaluate_expression(
"if(input_tokens < 100, if(output_tokens < 10, 0, 0.5), 1.5)",
{"input_tokens": 50, "output_tokens": 5},
),
)

Volume discounts: tier()​

tier(value, t1, r1, t2, r2, ..., default) selects the first rate whose upper bound exceeds the value and uses the last argument as the default. The example output rate is 0.01 under 1,000 tokens, 0.008 under 10,000, and 0.006 beyond.

curve = "tier(output_tokens, 1000, 0.01, 10000, 0.008, 0.006)"
print("small batch:", evaluate_expression(curve, {"output_tokens": 500}))
print("mid batch: ", evaluate_expression(curve, {"output_tokens": 5000}))
print("big batch: ", evaluate_expression(curve, {"output_tokens": 50000}))

Hard bounds: clamp()​

clamp(x, lo, hi) pins a value into a closed range — a minimum charge that is also capped, in one call.

print("clamp low: ", evaluate_expression("clamp(input_tokens * 2, 10, 100)", {"input_tokens": 4}))
print("clamp mid: ", evaluate_expression("clamp(input_tokens * 2, 10, 100)", {"input_tokens": 30}))
print("clamp high:", evaluate_expression("clamp(input_tokens * 2, 10, 100)", {"input_tokens": 60}))

Rounding: ceil(), floor(), round()​

ceil and floor round whole units — handy for pricing by started units (an execution billed per started minute). round(x, 2) rounds to decimal places with ROUND_HALF_UP, the same convention the engine uses for credit amounts.

print("ceil: ", evaluate_expression("ceil(input_tokens / 3)", {"input_tokens": 10}))
print("floor:", evaluate_expression("floor(input_tokens / 3)", {"input_tokens": 10}))
print("round:", evaluate_expression("round(input_tokens * 3.14159, 2)", {"input_tokens": 1}))

Percentiles, and a realistic formula​

percentile(p, v1, v2, ...) interpolates the p-th percentile of its arguments. The language requires at least one measure reference, so the first sample is the current metric's value. Then a realistic combined formula: volume-discounted input rate, flat output rate, 4-decimal rounding, and a hard clamp — for 5,000 + 1,000 tokens the tier picks 0.004, so 0.004 * 5000 + 0.015 * 1000 = 35.0000.

print("median:", evaluate_expression("percentile(50, input_tokens, 2, 3, 4)", {"input_tokens": 1}))
print("p90: ", evaluate_expression("percentile(90, input_tokens, 2, 3, 4)", {"input_tokens": 1}))

combined = (
"clamp(round("
"tier(input_tokens, 1000, 0.005, 100000, 0.004, 0.003) * input_tokens"
" + output_tokens * 0.015, 4), 0, 500)"
)
print("combined:", evaluate_expression(combined, {"input_tokens": 5000, "output_tokens": 1000}))

The sandbox: what the language refuses​

Expressions are stored in config and evaluated by the engine — code from a config file is an attack surface, so the language is a locked-down subset of arithmetic and functions. There is no way to reach Python:

  • ** exponentiation is rejected outright.
  • Builtins like __import__ are not in the language — a formula can never touch os, files, or the network. (__import__('os') below is exactly the kind of string that would be dangerous in eval, and exactly what the parser refuses.)
  • Division by zero raises a clear ExpressionError.
  • An undefined variable raises, rather than silently evaluating to something.

The same validation runs at config-load time against the operation's declared measures: a formula referencing an undeclared measure fails load_config_from_dict, and a formula with no measure reference at all is rejected too.

try:
evaluate_expression("input_tokens ** 2", {"input_tokens": 2})
except ExpressionError as error:
print("pow ->", type(error).__name__, "|", error)

try:
evaluate_expression("__import__('os')", {"input_tokens": 2})
except ExpressionError as error:
print("builtin ->", type(error).__name__, "|", error)

try:
evaluate_expression("input_tokens / 0", {"input_tokens": 2})
except ExpressionError as error:
print("div by zero ->", type(error).__name__, "|", error)

try:
evaluate_expression("bogus * 2", {"input_tokens": 2})
except ExpressionError as error:
print("undefined var ->", type(error).__name__, "|", error)

# The same rules apply at config-load time, scoped to declared measures.
try:
validate_expression("input_tokens * 2 + widgets", {"input_tokens"})
except ExpressionError as error:
print("validate ->", type(error).__name__, "|", error)

from shared import base_config
from bursar.config import load_config_from_dict, ConfigError

config = base_config()
config["pricing"]["rate_cards"]["standard"]["operations"]["completion"]["rules"][0]["charge"] = {
"type": "expression",
"formula": "input_tokens * 0.0025 + widgets * 5",
}
try:
load_config_from_dict(config)
except ConfigError as error:
print("config undeclared measure ->", type(error).__name__, "|", error)

constant_only = base_config()
constant_only["pricing"]["rate_cards"]["standard"]["operations"]["completion"]["rules"][0]["charge"] = {
"type": "expression",
"formula": "5 + 3",
}
try:
load_config_from_dict(constant_only)
except ConfigError as error:
print("config constant-only ->", type(error).__name__, "|", error)