Skip to main content

Expression Reference

ducto uses a safe expression language for pricing formulas. Same syntax works identically in Python and JavaScript.

Arithmetic

OperatorExampleDescription
+input_tokens * 0.01 + output_tokens * 0.03Addition
--cache_read_tokens * 0.001Subtraction / negation
*input_tokens * 0.01Multiplication
/output_tokens * (0.03 / 1000)Division
//input_tokens // 1000Floor division
%input_tokens % 1000Modulo
**input_tokens ** 2Exponentiation

Comparisons

OperatorExample
==output_tokens == 0
!=output_tokens != 0
<output_tokens < 1000
<=output_tokens <= 1000
>output_tokens > 1000
>=output_tokens >= 1000
in"gpt-4" in model
not in"batch" not in job_type

Boolean

OperatorExample
andtool_calls > 0 and tool_calls <= 10
ortool_calls == 0 or cache_read_tokens > 0
not5 if not (tool_calls > 10) else 10

Ternary

Python-style conditional expression:

output_tokens * 0.5 if output_tokens > 1000 else output_tokens * 0.3

Functions

FunctionDescriptionExample
ceil(x)Round upceil(input_tokens * 0.001)
floor(x)Round downfloor(output_tokens / 1000)
round(x)Nearest integerround(input_tokens * 0.001)
min(a, b, ...)Minimum of valuesmin(cost_a, cost_b)
max(a, b, ...)Maximum of valuesmax(0, model_cost - allowance)
if(cond, then, else)Conditionalif(input_tokens > 1000, cost_a, cost_b)
tier(val, t1, r1, t2, r2, ..., default)Tiered pricingtier(input_tokens, 0, 0, 10000, 5, 100000, 10)
clamp(x, lo, hi)Range clampclamp(tool_calls, 0, 100)
percentile(p, v1, v2, ...)Percentile of valuespercentile(95, model_cost_1, model_cost_2)

tier() details

Evaluates thresholds sequentially: returns r1 if val < t1, r2 if val < t2, ..., else default.

tier(input_tokens, 0, 0, 10000, 5, 100000, 10)
# 0-9999 → 0, 10000-99999 → 5, 100000+ → 10

percentile() details

Sorts values, computes p-th percentile (0–100) via linear interpolation.

percentile(50, input_tokens, output_tokens, tool_calls) # median of 3 values
percentile(0, a, b, c) # min
percentile(100, a, b, c) # max

Available Variables

VariableSource (Python)Source (JS)
input_tokensUsageMetrics.input_tokensinputTokens
output_tokensUsageMetrics.output_tokensoutputTokens
cache_read_tokensUsageMetrics.cache_read_tokenscacheReadTokens
cache_write_tokensUsageMetrics.cache_write_tokenscacheWriteTokens
tool_callslen(UsageMetrics.tool_calls)toolCalls.length
search_queriesUsageMetrics.search_queriessearchQueries
search_resultsUsageMetrics.search_resultssearchResults
web_search_callsUsageMetrics.web_search_callswebSearchCalls
code_exec_callsUsageMetrics.code_exec_callscodeExecCalls

Safety

  • Python: AST-based validator with strict node allowlist. No eval(), no attribute access, no imports.
  • JavaScript: Recursive descent parser with strict allowlist. No eval(), no Function() constructor.
  • All expressions validated at config load time. Invalid configs never reach the engine.