v0.4.0 — Dynamic subject and action fields on @cycles
What's Changed
The @cycles decorator now accepts callables on every previously-static field — six subject fields (tenant, workspace, app, workflow, agent, toolset), three action fields (action_kind, action_name, action_tags), and dimensions. Callables are invoked with the decorated function's *args, **kwargs at reservation time, enabling per-call budget routing and dynamic action labeling.
@cycles(
estimate=lambda req, workspace_id: req.tokens * 10,
workspace=lambda req, workspace_id: workspace_id, # per-call routing
action_kind=lambda req, *_: f"llm.{req.provider}", # dynamic label
action_name=lambda req, *_: req.model,
dimensions=lambda req, *_: {"region": req.region},
)
def run_request(req: ResponseRequest, workspace_id: str) -> Response: ...Mirrors the existing estimate / actual callable contract and re-aligns the Python client with the Java client's SpEL behavior shipped in cycles-spring-boot-starter 0.2.1.
Fallback semantics (preserved)
- Subject callables returning
Nonefall through to the client-config default. action_kind/action_namereturningNonefall through to"unknown".action_tags/dimensionsreturningNoneare omitted from the request.- Exceptions in user callables propagate fail-fast without creating a reservation.
No protocol or wire-format changes.
- feat(decorator): support callables on subject and action fields by @amavashev in #46
Test coverage: 100% across all 13 modules (389 tests).
Full Changelog: v0.3.0...v0.4.0