Feature tagging
Attribute agent cost to product features and users — the default feature, radicas.feature() scoping, and radicas.user() for per-user allocation.
Radicas allocates cost by feature — the product capability an agent invocation serves —
via the radicas.feature span attribute, and by user via user.id. The SDK stamps both
for you.
The default feature
Set once at init; stamped on every agent invocation (invoke_agent span):
radicas.init(service="pricing-agent", feature="flight-pricing")or RADICAS_FEATURE=flight-pricing in the environment (legacy FEATURE_NAME also works).
Per-request scoping: radicas.feature()
When one process serves several features, override the default for a block:
with radicas.feature("re-pricing-batch"):
agent.run(prompt) # this invocation is allocated to re-pricing-batch
agent.run(prompt2) # back to the init() defaultInside the block, the override is stamped on the invoke_agent root and every child span
(so the whole subtree is marked); outside it, only invocation roots carry the default.
Per-user allocation: radicas.user()
user.id feeds per-user cost allocation (who is driving the spend):
with radicas.user(request.user_id):
agent.run(prompt)Both context managers nest and compose:
with radicas.feature("chat-assist"), radicas.user("u-42"):
agent.run(prompt)Propagation and its limits
The overrides ride the OpenTelemetry context, so they follow:
- normal synchronous call stacks,
asynciotasks created inside the block,- threads and executors that propagate OTel context (OTel-instrumented executors, or manually attaching a captured context in the worker).
Limitation — raw threads: a plain threading.Thread(target=...) started inside the block
does not inherit the OTel context, so spans created there fall back to the init default.
Either attach a captured context in the worker:
from opentelemetry import context as otel_context
ctx = otel_context.get_current() # capture inside the with-block
def worker():
token = otel_context.attach(ctx) # re-attach in the thread
try:
agent.run(prompt)
finally:
otel_context.detach(token)or set the feature at init() when the whole process serves one feature.
Naming guidance
- Name product features, not code paths:
flight-pricing,refund-triage,support-chat— the names appear in cost dashboards read by non-engineers. - Use stable, lowercase, hyphenated slugs; renaming a feature splits its cost history.
- Keep cardinality low (dozens, not thousands). For per-request identifiers use
user.idor the conversation id — not the feature tag. - The fallback feature is literally
default: if you see it in the dashboard, an agent is running without a configured feature.
Authentication
API key lifecycle, Bearer transport, and why the client never sends a tenant id — Radicas' anti-spoof tenancy model.
Telemetry reference
The canonical contract the SDK emits — span tree, full attribute table including token and cache-token usage, content events, and what Radicas computes from each field.