-
-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(docs) Document StandardLoggingPayload Spec (#7201)
* add slp spec to docs * docs slp * test slp enforcement
- Loading branch information
1 parent
431c86c
commit 621c713
Showing
4 changed files
with
195 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
|
||
# StandardLoggingPayload Specification | ||
|
||
Found under `kwargs["standard_logging_object"]`. This is a standard payload, logged for every successful and failed response. | ||
|
||
## StandardLoggingPayload | ||
|
||
| Field | Type | Description | | ||
|-------|------|-------------| | ||
| `id` | `str` | Unique identifier | | ||
| `trace_id` | `str` | Trace multiple LLM calls belonging to same overall request | | ||
| `call_type` | `str` | Type of call | | ||
| `response_cost` | `float` | Cost of the response in USD ($) | | ||
| `response_cost_failure_debug_info` | `StandardLoggingModelCostFailureDebugInformation` | Debug information if cost tracking fails | | ||
| `status` | `StandardLoggingPayloadStatus` | Status of the payload | | ||
| `total_tokens` | `int` | Total number of tokens | | ||
| `prompt_tokens` | `int` | Number of prompt tokens | | ||
| `completion_tokens` | `int` | Number of completion tokens | | ||
| `startTime` | `float` | Start time of the call | | ||
| `endTime` | `float` | End time of the call | | ||
| `completionStartTime` | `float` | Time to first token for streaming requests | | ||
| `response_time` | `float` | Total response time. If streaming, this is the time to first token | | ||
| `model_map_information` | `StandardLoggingModelInformation` | Model mapping information | | ||
| `model` | `str` | Model name sent in request | | ||
| `model_id` | `Optional[str]` | Model ID of the deployment used | | ||
| `model_group` | `Optional[str]` | `model_group` used for the request | | ||
| `api_base` | `str` | LLM API base URL | | ||
| `metadata` | `StandardLoggingMetadata` | Metadata information | | ||
| `cache_hit` | `Optional[bool]` | Whether cache was hit | | ||
| `cache_key` | `Optional[str]` | Optional cache key | | ||
| `saved_cache_cost` | `float` | Cost saved by cache | | ||
| `request_tags` | `list` | List of request tags | | ||
| `end_user` | `Optional[str]` | Optional end user identifier | | ||
| `requester_ip_address` | `Optional[str]` | Optional requester IP address | | ||
| `messages` | `Optional[Union[str, list, dict]]` | Messages sent in the request | | ||
| `response` | `Optional[Union[str, list, dict]]` | LLM response | | ||
| `error_str` | `Optional[str]` | Optional error string | | ||
| `error_information` | `Optional[StandardLoggingPayloadErrorInformation]` | Optional error information | | ||
| `model_parameters` | `dict` | Model parameters | | ||
| `hidden_params` | `StandardLoggingHiddenParams` | Hidden parameters | | ||
|
||
## StandardLoggingUserAPIKeyMetadata | ||
|
||
| Field | Type | Description | | ||
|-------|------|-------------| | ||
| `user_api_key_hash` | `Optional[str]` | Hash of the litellm virtual key | | ||
| `user_api_key_alias` | `Optional[str]` | Alias of the API key | | ||
| `user_api_key_org_id` | `Optional[str]` | Organization ID associated with the key | | ||
| `user_api_key_team_id` | `Optional[str]` | Team ID associated with the key | | ||
| `user_api_key_user_id` | `Optional[str]` | User ID associated with the key | | ||
| `user_api_key_team_alias` | `Optional[str]` | Team alias associated with the key | | ||
|
||
## StandardLoggingMetadata | ||
|
||
Inherits from `StandardLoggingUserAPIKeyMetadata` and adds: | ||
|
||
| Field | Type | Description | | ||
|-------|------|-------------| | ||
| `spend_logs_metadata` | `Optional[dict]` | Key-value pairs for spend logging | | ||
| `requester_ip_address` | `Optional[str]` | Requester's IP address | | ||
| `requester_metadata` | `Optional[dict]` | Additional requester metadata | | ||
|
||
## StandardLoggingAdditionalHeaders | ||
|
||
| Field | Type | Description | | ||
|-------|------|-------------| | ||
| `x_ratelimit_limit_requests` | `int` | Rate limit for requests | | ||
| `x_ratelimit_limit_tokens` | `int` | Rate limit for tokens | | ||
| `x_ratelimit_remaining_requests` | `int` | Remaining requests in rate limit | | ||
| `x_ratelimit_remaining_tokens` | `int` | Remaining tokens in rate limit | | ||
|
||
## StandardLoggingHiddenParams | ||
|
||
| Field | Type | Description | | ||
|-------|------|-------------| | ||
| `model_id` | `Optional[str]` | Optional model ID | | ||
| `cache_key` | `Optional[str]` | Optional cache key | | ||
| `api_base` | `Optional[str]` | Optional API base URL | | ||
| `response_cost` | `Optional[str]` | Optional response cost | | ||
| `additional_headers` | `Optional[StandardLoggingAdditionalHeaders]` | Additional headers | | ||
|
||
## StandardLoggingModelInformation | ||
|
||
| Field | Type | Description | | ||
|-------|------|-------------| | ||
| `model_map_key` | `str` | Model map key | | ||
| `model_map_value` | `Optional[ModelInfo]` | Optional model information | | ||
|
||
## StandardLoggingModelCostFailureDebugInformation | ||
|
||
| Field | Type | Description | | ||
|-------|------|-------------| | ||
| `error_str` | `str` | Error string | | ||
| `traceback_str` | `str` | Traceback string | | ||
| `model` | `str` | Model name | | ||
| `cache_hit` | `Optional[bool]` | Whether cache was hit | | ||
| `custom_llm_provider` | `Optional[str]` | Optional custom LLM provider | | ||
| `base_model` | `Optional[str]` | Optional base model | | ||
| `call_type` | `str` | Call type | | ||
| `custom_pricing` | `Optional[bool]` | Whether custom pricing was used | | ||
|
||
## StandardLoggingPayloadErrorInformation | ||
|
||
| Field | Type | Description | | ||
|-------|------|-------------| | ||
| `error_code` | `Optional[str]` | Optional error code (eg. "429") | | ||
| `error_class` | `Optional[str]` | Optional error class (eg. "RateLimitError") | | ||
| `llm_provider` | `Optional[str]` | LLM provider that returned the error (eg. "openai")` | | ||
|
||
## StandardLoggingPayloadStatus | ||
|
||
A literal type with two possible values: | ||
- `"success"` | ||
- `"failure"` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
79 changes: 79 additions & 0 deletions
79
tests/documentation_tests/test_standard_logging_payload.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import os | ||
import re | ||
import sys | ||
|
||
from typing import get_type_hints | ||
|
||
sys.path.insert( | ||
0, os.path.abspath("../..") | ||
) # Adds the parent directory to the system path | ||
|
||
from litellm.types.utils import StandardLoggingPayload | ||
|
||
|
||
def get_all_fields(type_dict, prefix=""): | ||
"""Recursively get all fields from TypedDict and its nested types""" | ||
fields = set() | ||
|
||
# Get type hints for the TypedDict | ||
hints = get_type_hints(type_dict) | ||
|
||
for field_name, field_type in hints.items(): | ||
full_field_name = f"{prefix}{field_name}" if prefix else field_name | ||
fields.add(full_field_name) | ||
|
||
# Check if the field type is another TypedDict we should process | ||
if hasattr(field_type, "__annotations__"): | ||
nested_fields = get_all_fields(field_type) | ||
fields.update(nested_fields) | ||
return fields | ||
|
||
|
||
def test_standard_logging_payload_documentation(): | ||
# Get all fields from StandardLoggingPayload and its nested types | ||
all_fields = get_all_fields(StandardLoggingPayload) | ||
|
||
print("All fields in StandardLoggingPayload: ") | ||
for _field in all_fields: | ||
print(_field) | ||
|
||
# Read the documentation | ||
docs_path = "../../docs/my-website/docs/proxy/logging_spec.md" | ||
|
||
try: | ||
with open(docs_path, "r", encoding="utf-8") as docs_file: | ||
content = docs_file.read() | ||
|
||
# Extract documented fields from the table | ||
doc_field_pattern = re.compile(r"\|\s*`([^`]+?)`\s*\|") | ||
documented_fields = set(doc_field_pattern.findall(content)) | ||
|
||
# Clean up documented fields (remove whitespace) | ||
documented_fields = {field.strip() for field in documented_fields} | ||
|
||
# Clean up documented fields (remove whitespace) | ||
documented_fields = {field.strip() for field in documented_fields} | ||
print("\n\nDocumented fields: ") | ||
for _field in documented_fields: | ||
print(_field) | ||
|
||
# Compare and find undocumented fields | ||
undocumented_fields = all_fields - documented_fields | ||
|
||
print("\n\nUndocumented fields: ") | ||
for _field in undocumented_fields: | ||
print(_field) | ||
|
||
if undocumented_fields: | ||
raise Exception( | ||
f"\nFields not documented in 'StandardLoggingPayload': {undocumented_fields}" | ||
) | ||
|
||
print( | ||
f"All {len(all_fields)} fields are documented in 'StandardLoggingPayload'" | ||
) | ||
|
||
except FileNotFoundError: | ||
raise Exception( | ||
f"Documentation file not found at {docs_path}. Please ensure the documentation exists." | ||
) |