dify/api/core/model_context.py
林玮 (Jade Lin) 960018253b
feat(api): track credit usage contexts (#41181)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-08-25 10:21:32 +00:00

62 lines
1.9 KiB
Python

from collections.abc import Callable, Generator, Mapping
from contextlib import contextmanager
from contextvars import ContextVar
from functools import wraps
from typing import Any, Protocol, cast
from core.credit_usage import CreditUsageCreatedByInput, normalize_credit_usage_created_by
_credit_usage_metadata: ContextVar[dict[str, object] | None] = ContextVar(
"credit_usage_metadata",
default=None,
)
class _CreditUsageMetadataCarrier(Protocol):
_request_metadata: Mapping[str, object] | None
def get_credit_usage_metadata() -> Mapping[str, object] | None:
return _credit_usage_metadata.get()
@contextmanager
def use_credit_usage_metadata(metadata: Mapping[str, object] | None) -> Generator[None, None, None]:
if metadata is None:
yield
return
current_metadata = _credit_usage_metadata.get()
effective_metadata = {**metadata, **(current_metadata or {})}
token = _credit_usage_metadata.set(effective_metadata)
try:
yield
finally:
_credit_usage_metadata.reset(token)
def with_credit_usage_metadata(method: Callable[..., Any]) -> Callable[..., Any]:
@wraps(method)
def wrapper(self, *args: object, **kwargs: object):
carrier = cast(_CreditUsageMetadataCarrier, self)
with use_credit_usage_metadata(carrier._request_metadata):
return method(self, *args, **kwargs)
return wrapper
def with_credit_usage_created_by(
created_by: CreditUsageCreatedByInput,
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
normalized_created_by = normalize_credit_usage_created_by(created_by)
def decorator(method: Callable[..., Any]) -> Callable[..., Any]:
@wraps(method)
def wrapper(*args: object, **kwargs: object):
with use_credit_usage_metadata({"created_by": normalized_created_by}):
return method(*args, **kwargs)
return wrapper
return decorator