API Reference
admin
Admin module for Luthien Control.
auth
Authentication logic for admin users.
AdminAuthService
Source code in luthien_control/admin/auth.py
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
|
Service for admin authentication operations.
authenticate(db, username, password)
async
Source code in luthien_control/admin/auth.py
38 39 40 41 42 43 44 |
|
Authenticate admin user.
create_session(db, admin_user)
async
Source code in luthien_control/admin/auth.py
46 47 48 49 50 51 |
|
Create a new session for authenticated user.
ensure_default_admin(db)
async
Source code in luthien_control/admin/auth.py
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
Ensure a default admin user exists.
get_user_from_session(db, session_token)
async
Source code in luthien_control/admin/auth.py
53 54 55 56 57 58 59 60 61 62 63 |
|
Get admin user from session token.
logout(db, session_token)
async
Source code in luthien_control/admin/auth.py
65 66 67 |
|
Logout by deleting session.
crud
Admin CRUD operations.
admin_user
CRUD operations for admin users.
AdminSessionCRUD
Source code in luthien_control/admin/crud/admin_user.py
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
|
CRUD operations for admin sessions.
cleanup_expired_sessions(db)
async
Source code in luthien_control/admin/crud/admin_user.py
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
|
Clean up expired sessions.
create_session(db, admin_user_id, hours=24)
async
Source code in luthien_control/admin/crud/admin_user.py
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
|
Create a new admin session.
delete_session(db, session_token)
async
Source code in luthien_control/admin/crud/admin_user.py
99 100 101 102 103 104 105 106 107 108 109 |
|
Delete a session (logout).
get_valid_session(db, session_token)
async
Source code in luthien_control/admin/crud/admin_user.py
87 88 89 90 91 92 93 94 95 96 97 |
|
Get a valid (non-expired) session by token.
AdminUserCRUD
Source code in luthien_control/admin/crud/admin_user.py
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
|
CRUD operations for admin users.
create(db, username, password, is_superuser=False)
async
Source code in luthien_control/admin/crud/admin_user.py
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
Create a new admin user.
get_by_id(db, user_id)
async
Source code in luthien_control/admin/crud/admin_user.py
22 23 24 25 |
|
Get admin user by ID.
get_by_username(db, username)
async
Source code in luthien_control/admin/crud/admin_user.py
17 18 19 20 |
|
Get admin user by username.
list_all(db)
async
Source code in luthien_control/admin/crud/admin_user.py
62 63 64 65 |
|
List all admin users.
verify_password(db, username, password)
async
Source code in luthien_control/admin/crud/admin_user.py
48 49 50 51 52 53 54 55 56 57 58 59 60 |
|
Verify username and password.
dependencies
Dependencies for admin authentication.
CSRFProtection
Source code in luthien_control/admin/dependencies.py
34 35 36 37 38 39 40 41 42 43 44 |
|
CSRF protection for forms.
generate_token()
async
Source code in luthien_control/admin/dependencies.py
40 41 42 43 44 |
|
Generate CSRF token.
get_current_admin(session_token=None, db=Depends(get_db_session))
async
Source code in luthien_control/admin/dependencies.py
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
Get current authenticated admin user from session cookie.
router
Admin router for authentication and policy management.
admin_home(request, current_admin, db=Depends(get_db_session))
async
Source code in luthien_control/admin/router.py
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
|
Admin dashboard hub.
create_policy_handler(request, name, type, config, current_admin, db=Depends(get_db_session), description=None, is_active=False, csrf_token='')
async
Source code in luthien_control/admin/router.py
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 |
|
Handle new policy creation.
edit_policy_page(request, policy_name, current_admin, db=Depends(get_db_session))
async
Source code in luthien_control/admin/router.py
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
|
Display policy edit page.
login(request, response, username, password, csrf_token, db=Depends(get_db_session))
async
Source code in luthien_control/admin/router.py
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
|
Handle login form submission.
login_page(request)
async
Source code in luthien_control/admin/router.py
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
|
Display login page.
logout(request, db=Depends(get_db_session))
async
Source code in luthien_control/admin/router.py
113 114 115 116 117 118 119 120 121 122 123 124 125 |
|
Logout and redirect to login page.
new_policy_page(request, current_admin)
async
Source code in luthien_control/admin/router.py
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
|
Display new policy creation page.
policies_list(request, current_admin, db=Depends(get_db_session))
async
Source code in luthien_control/admin/router.py
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
|
List all control policies.
update_policy_handler(request, policy_name, config, current_admin, db=Depends(get_db_session), description=None, is_active=False, csrf_token='')
async
Source code in luthien_control/admin/router.py
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
|
Handle policy update form submission.
api
openai_chat_completions
Choice
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
68 69 70 71 72 73 74 |
|
A single choice in a chat completion response.
CompletionTokensDetails
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
84 85 86 87 88 89 90 |
|
Details about completion token usage.
ContentPartImage
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
120 121 122 123 124 |
|
An image content part.
ContentPartText
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
113 114 115 116 117 |
|
A text content part.
FunctionDefinition
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
137 138 139 140 141 142 |
|
The definition of a function that can be called by the model.
ImageUrl
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
106 107 108 109 110 |
|
The image URL details.
LogProbs
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
61 62 63 64 65 |
|
Log probability information for the choice.
Message
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
49 50 51 52 53 54 55 56 57 58 |
|
A message in a chat completion.
OpenAIChatCompletionsRequest
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/request.py
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
|
Request context for OpenAI chat completions.
Based on the OpenAI API reference: https://platform.openai.com/docs/api-reference/chat/create?lang=python (retrieved 2025-06-16)
This model is evented and will emit a changed
signal on any modification.
OpenAIChatCompletionsResponse
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/response.py
14 15 16 17 18 19 20 21 22 23 24 |
|
The request for a chat completion.
PromptTokensDetails
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
77 78 79 80 81 |
|
Details about prompt token usage.
ResponseFormat
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
127 128 129 130 131 132 133 134 |
|
An object specifying the format that the model must output.
See https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses
ToolChoice
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
158 159 160 161 162 |
|
A specific tool choice.
ToolChoiceFunction
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
152 153 154 155 |
|
The function to call in a tool choice.
ToolDefinition
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
145 146 147 148 149 |
|
A tool that can be used by the model.
Usage
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
93 94 95 96 97 98 99 100 |
|
Token usage statistics for the chat completion request.
datatypes
Choice
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
68 69 70 71 72 73 74 |
|
A single choice in a chat completion response.
CompletionTokensDetails
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
84 85 86 87 88 89 90 |
|
Details about completion token usage.
ContentPartImage
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
120 121 122 123 124 |
|
An image content part.
ContentPartText
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
113 114 115 116 117 |
|
A text content part.
FunctionDefinition
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
137 138 139 140 141 142 |
|
The definition of a function that can be called by the model.
ImageUrl
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
106 107 108 109 110 |
|
The image URL details.
LogProbs
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
61 62 63 64 65 |
|
Log probability information for the choice.
Message
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
49 50 51 52 53 54 55 56 57 58 |
|
A message in a chat completion.
PromptTokensDetails
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
77 78 79 80 81 |
|
Details about prompt token usage.
RequestFunctionCall
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
165 166 167 168 |
|
A function call in a request.
ResponseFormat
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
127 128 129 130 131 132 133 134 |
|
An object specifying the format that the model must output.
See https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses
ToolChoice
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
158 159 160 161 162 |
|
A specific tool choice.
ToolChoiceFunction
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
152 153 154 155 |
|
The function to call in a tool choice.
ToolDefinition
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
145 146 147 148 149 |
|
A tool that can be used by the model.
Usage
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/datatypes.py
93 94 95 96 97 98 99 100 |
|
Token usage statistics for the chat completion request.
request
OpenAIChatCompletionsRequest
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/request.py
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
|
Request context for OpenAI chat completions.
Based on the OpenAI API reference: https://platform.openai.com/docs/api-reference/chat/create?lang=python (retrieved 2025-06-16)
This model is evented and will emit a changed
signal on any modification.
response
OpenAIChatCompletionsResponse
Bases: DeepEventedModel
Source code in luthien_control/api/openai_chat_completions/response.py
14 15 16 17 18 19 20 21 22 23 24 |
|
The request for a chat completion.
control_policy
add_api_key_header
AddApiKeyHeaderPolicy
Bases: ControlPolicy
Source code in luthien_control/control_policy/add_api_key_header.py
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
|
Adds the configured OpenAI API key to the request Authorization header.
This policy reads the API key from the application settings and adds it to the request. It has no policy-specific configuration beyond its name.
apply(transaction, container, session)
async
Source code in luthien_control/control_policy/add_api_key_header.py
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
|
Sets the API key on the transaction's request.
Reads OpenAI API key from settings via the container. Requires the DependencyContainer and AsyncSession in signature for interface compliance, but session is not directly used in this policy's logic.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
transaction
|
Transaction
|
The current transaction. |
required |
container
|
DependencyContainer
|
The application dependency container. |
required |
session
|
AsyncSession
|
An active SQLAlchemy AsyncSession (unused). |
required |
Returns:
Type | Description |
---|---|
Transaction
|
The potentially modified transaction. |
add_api_key_header_from_env
Add an API key header, where the key is sourced from a configured environment variable.
This policy is used to add an API key to the request Authorization header. The API key is read from an environment variable whose name is configured when the policy is instantiated.
AddApiKeyHeaderFromEnvPolicy
Bases: ControlPolicy
Source code in luthien_control/control_policy/add_api_key_header_from_env.py
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
|
Adds an API key to the request Authorization header from an environment variable.
The API key is read from an environment variable whose name is configured when the policy is instantiated. This allows different API keys to be used based on deployment environment.
apply(transaction, container, session)
async
Source code in luthien_control/control_policy/add_api_key_header_from_env.py
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
|
Sets the API key on the transaction's request.
The API key is read from the environment variable specified by self.api_key_env_var_name. Requires DependencyContainer and AsyncSession for interface compliance, but they are not directly used in this policy's primary logic beyond what ControlPolicy might require.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
transaction
|
Transaction
|
The current transaction. |
required |
container
|
DependencyContainer
|
The application dependency container (unused). |
required |
session
|
AsyncSession
|
An active SQLAlchemy AsyncSession (unused). |
required |
Returns:
Type | Description |
---|---|
Transaction
|
The potentially modified transaction. |
backend_call_policy
BackendCallPolicy
Bases: ControlPolicy
Source code in luthien_control/control_policy/backend_call_policy.py
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
|
This policy makes a backend LLM call.
branching_policy
BranchingPolicy
Bases: ControlPolicy
Source code in luthien_control/control_policy/branching_policy.py
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
|
A Control Policy that conditionally applies different policies based on transaction evaluation.
This policy evaluates conditions in order and applies the policy associated with the first matching condition. If no conditions match, it applies the default policy (if configured).
apply(transaction, container, session)
async
Source code in luthien_control/control_policy/branching_policy.py
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
|
Apply the first policy that matches the condition. If no condition matches, apply the default policy (if set).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
transaction
|
Transaction
|
The transaction to apply the policy to. |
required |
container
|
DependencyContainer
|
The dependency container. |
required |
session
|
AsyncSession
|
The database session. |
required |
Returns:
Type | Description |
---|---|
Transaction
|
The potentially modified transaction. |
from_serialized(config)
classmethod
Source code in luthien_control/control_policy/branching_policy.py
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
|
Custom from_serialized to handle JSON-serialized condition keys.
serialize()
Source code in luthien_control/control_policy/branching_policy.py
67 68 69 70 71 72 73 74 75 76 77 |
|
Override serialize to handle complex condition-to-policy mapping.
validate_cond_to_policy_map(value)
classmethod
Source code in luthien_control/control_policy/branching_policy.py
30 31 32 33 34 35 36 37 38 |
|
Validate and convert condition-to-policy mapping.
validate_default_policy(value)
classmethod
Source code in luthien_control/control_policy/branching_policy.py
40 41 42 43 44 |
|
Validate default policy field.
client_api_key_auth
ClientApiKeyAuthPolicy
Bases: ControlPolicy
Source code in luthien_control/control_policy/client_api_key_auth.py
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
|
Verifies the client API key from the transaction's request.
This policy authenticates clients by checking their API key against the database. It ensures the key exists and is active.
Attributes:
Name | Type | Description |
---|---|---|
name |
str
|
The name of this policy instance. |
apply(transaction, container, session)
async
Source code in luthien_control/control_policy/client_api_key_auth.py
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
|
Verifies the API key from the transaction's request. Requires the DependencyContainer and an active SQLAlchemy AsyncSession.
Raises:
Type | Description |
---|---|
NoRequestError
|
If transaction.request is None. |
ClientAuthenticationError
|
If the key is missing, invalid, or inactive. |
Parameters:
Name | Type | Description | Default |
---|---|---|---|
transaction
|
Transaction
|
The current transaction. |
required |
container
|
DependencyContainer
|
The application dependency container. |
required |
session
|
AsyncSession
|
An active SQLAlchemy AsyncSession. |
required |
Returns:
Type | Description |
---|---|
Transaction
|
The unmodified transaction if authentication is successful. |
conditions
AllCondition
Bases: Condition
Source code in luthien_control/control_policy/conditions/all_cond.py
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
serialize_conditions(value)
Source code in luthien_control/control_policy/conditions/all_cond.py
13 14 15 16 |
|
Custom serializer for conditions field.
validate_conditions(value)
classmethod
Source code in luthien_control/control_policy/conditions/all_cond.py
18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Custom validator to deserialize conditions from dicts.
AnyCondition
Bases: Condition
Source code in luthien_control/control_policy/conditions/any_cond.py
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
serialize_conditions(value)
Source code in luthien_control/control_policy/conditions/any_cond.py
13 14 15 16 |
|
Custom serializer for conditions field.
validate_conditions(value)
classmethod
Source code in luthien_control/control_policy/conditions/any_cond.py
18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Custom validator to deserialize conditions from dicts.
Condition
Bases: BaseModel
, ABC
Source code in luthien_control/control_policy/conditions/condition.py
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
|
Abstract base class for conditions in control policies.
Conditions are used to evaluate whether a policy should be applied based on the current transaction.
from_serialized(serialized)
classmethod
Source code in luthien_control/control_policy/conditions/condition.py
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
|
Construct a condition from a serialized configuration.
This method acts as a dispatcher. It looks up the concrete condition class based on the 'type' field in the config and delegates to its from_serialized method.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
serialized
|
SerializableDict
|
The condition-specific configuration dictionary. It must contain a 'type' key that maps to a registered condition type. |
required |
Returns:
Type | Description |
---|---|
Condition
|
An instance of the concrete condition class. |
Raises:
Type | Description |
---|---|
ValueError
|
If the 'type' key is missing in config or the type is not registered. |
serialize()
Source code in luthien_control/control_policy/conditions/condition.py
24 25 26 27 28 |
|
Serialize using Pydantic model_dump through SerializableDict validation.
ContainsCondition
Bases: ComparisonCondition
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
226 227 228 229 230 231 232 |
|
Condition to check if the left value contains the right value.
EqualsCondition
Bases: ComparisonCondition
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
|
Condition to check if two values are equal.
Examples:
Traditional
EqualsCondition(path("request.payload.model"), "gpt-4o")
Dynamic
EqualsCondition(path("request.payload.model"), path("data.preferred_model"))
Static vs dynamic
EqualsCondition("gpt-4o", path("request.payload.model"))
GreaterThanCondition
Bases: ComparisonCondition
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
253 254 255 256 257 258 259 |
|
Condition to check if the left value is greater than the right value.
GreaterThanOrEqualCondition
Bases: ComparisonCondition
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
262 263 264 265 266 267 268 |
|
Condition to check if the left value is greater than or equal to the right value.
LessThanCondition
Bases: ComparisonCondition
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
235 236 237 238 239 240 241 |
|
Condition to check if the left value is less than the right value.
LessThanOrEqualCondition
Bases: ComparisonCondition
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
244 245 246 247 248 249 250 |
|
Condition to check if the left value is less than or equal to the right value.
NotCondition
Bases: Condition
Source code in luthien_control/control_policy/conditions/not_cond.py
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
serialize_cond(value)
Source code in luthien_control/control_policy/conditions/not_cond.py
13 14 15 16 |
|
Custom serializer for cond field.
validate_cond(value)
classmethod
Source code in luthien_control/control_policy/conditions/not_cond.py
18 19 20 21 22 23 24 |
|
Custom validator to deserialize condition from dict.
NotEqualsCondition
Bases: ComparisonCondition
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
217 218 219 220 221 222 223 |
|
Condition to check if two values are NOT equal.
RegexMatchCondition
Bases: ComparisonCondition
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
271 272 273 274 275 276 277 |
|
Condition to check if the left value matches a regex pattern.
path(transaction_path)
Source code in luthien_control/control_policy/conditions/value_resolvers.py
139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
|
Convenience function to create a TransactionPath.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
transaction_path
|
str
|
The path to the value in the transaction |
required |
Returns:
Type | Description |
---|---|
TransactionPath
|
A TransactionPath instance |
Example
path("request.payload.model")
all_cond
AllCondition
Bases: Condition
Source code in luthien_control/control_policy/conditions/all_cond.py
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
serialize_conditions(value)
Source code in luthien_control/control_policy/conditions/all_cond.py
13 14 15 16 |
|
Custom serializer for conditions field.
validate_conditions(value)
classmethod
Source code in luthien_control/control_policy/conditions/all_cond.py
18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Custom validator to deserialize conditions from dicts.
any_cond
AnyCondition
Bases: Condition
Source code in luthien_control/control_policy/conditions/any_cond.py
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
serialize_conditions(value)
Source code in luthien_control/control_policy/conditions/any_cond.py
13 14 15 16 |
|
Custom serializer for conditions field.
validate_conditions(value)
classmethod
Source code in luthien_control/control_policy/conditions/any_cond.py
18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Custom validator to deserialize conditions from dicts.
comparison_conditions
Comparison conditions for control policies.
This module implements comparison-based conditions (equals, contains, greater than, etc.) using a clean ValueResolver pattern for flexible value resolution.
Pyright Type Checker Suppression
The # pyright: reportCallIssue=false
comment at the top of this file suppresses type
checker warnings for positional argument usage in comparison condition constructors.
Why This Is Necessary
All comparison conditions inherit from Pydantic's BaseModel, which enforces keyword-only constructors. However, we provide a more natural API with positional arguments:
# Natural, concise syntax (what we want)
EqualsCondition(path("request.payload.model"), "gpt-4o")
# Verbose but type-safe (what Pydantic expects)
EqualsCondition(left=path("request.payload.model"), right="gpt-4o")
Our custom __init__
methods handle both patterns correctly at runtime, but static
analysis tools like pyright cannot see through the Pydantic inheritance to understand
this flexibility.
Safety Considerations
This suppression is safe because:
1. We only suppress reportCallIssue
(constructor signature mismatches)
2. Our overload definitions provide proper type hints
3. Runtime behavior is thoroughly tested
4. Other type checking (return types, field access, etc.) remains active
For Users of This Module
When using these comparison conditions in your code, you may encounter pyright warnings.
See the ComparisonCondition
class documentation for guidance on suppressing these
warnings appropriately in your own files.
ComparisonCondition
Bases: Condition
, ABC
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
|
Clean comparison condition that uses ValueResolver objects for flexible value resolution.
This approach eliminates the need for is_dynamic_* flags by using explicit types.
Constructor Usage
This class supports both positional and keyword argument patterns:
Positional Arguments (Recommended for brevity)
EqualsCondition(path("request.payload.model"), "gpt-4o")
EqualsCondition(path("left_path"), path("right_path")) # Dynamic comparison
EqualsCondition("static_left", "static_right") # Static comparison
Keyword Arguments (Explicit, type-safe)
EqualsCondition(left=path("request.payload.model"), right="gpt-4o")
EqualsCondition(left=path("left_path"), right=path("right_path"))
Pyright Type Checker Warning
Important: When using positional arguments, pyright may show this error:
Expected 0 positional arguments (reportCallIssue)
This is a known issue due to the underlying Pydantic BaseModel inheritance. The code
works correctly at runtime, but pyright's static analysis doesn't recognize our
custom __init__
override.
How to Suppress the Warning
Add this comment to suppress the specific error on individual calls:
condition = EqualsCondition(path("test"), "value") # pyright: ignore[reportCallIssue]
Or add this at the top of your file to suppress all such errors in that file:
# pyright: reportCallIssue=false
When to Use Each Approach
- Use positional: For concise, readable condition creation in tests and simple cases
- Use keywords: When you need full type safety or when working in strict typing environments
- Suppress warnings: When you prefer the positional syntax and understand the trade-off
__init__(left=None, right=None, *, comparator=None, **kwargs)
__init__(
left: Union[Any, ValueResolver],
right: Union[Any, ValueResolver],
) -> None
__init__(
*,
left: ValueResolver,
right: ValueResolver,
comparator: str,
**kwargs: Any,
) -> None
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
|
Initialize with both positional and keyword argument support.
evaluate(transaction)
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
174 175 176 177 178 |
|
Evaluate the condition against the transaction.
from_legacy_format(key, value)
classmethod
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
183 184 185 186 187 188 189 190 191 192 193 194 195 |
|
Create a condition from legacy ComparisonCondition format.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
key
|
str
|
Transaction path (e.g., "request.payload.model") |
required |
value
|
Any
|
Static value to compare against |
required |
Returns:
Type | Description |
---|---|
ComparisonCondition
|
A ComparisonCondition instance |
serialize_value_resolver(value)
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
160 161 162 163 |
|
Custom serializer for ValueResolver fields.
validate_value_resolver(value)
classmethod
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
165 166 167 168 169 170 171 172 |
|
Custom validator to deserialize ValueResolver from dict.
ContainsCondition
Bases: ComparisonCondition
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
226 227 228 229 230 231 232 |
|
Condition to check if the left value contains the right value.
EqualsCondition
Bases: ComparisonCondition
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
|
Condition to check if two values are equal.
Examples:
Traditional
EqualsCondition(path("request.payload.model"), "gpt-4o")
Dynamic
EqualsCondition(path("request.payload.model"), path("data.preferred_model"))
Static vs dynamic
EqualsCondition("gpt-4o", path("request.payload.model"))
GreaterThanCondition
Bases: ComparisonCondition
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
253 254 255 256 257 258 259 |
|
Condition to check if the left value is greater than the right value.
GreaterThanOrEqualCondition
Bases: ComparisonCondition
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
262 263 264 265 266 267 268 |
|
Condition to check if the left value is greater than or equal to the right value.
LessThanCondition
Bases: ComparisonCondition
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
235 236 237 238 239 240 241 |
|
Condition to check if the left value is less than the right value.
LessThanOrEqualCondition
Bases: ComparisonCondition
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
244 245 246 247 248 249 250 |
|
Condition to check if the left value is less than or equal to the right value.
NotEqualsCondition
Bases: ComparisonCondition
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
217 218 219 220 221 222 223 |
|
Condition to check if two values are NOT equal.
RegexMatchCondition
Bases: ComparisonCondition
Source code in luthien_control/control_policy/conditions/comparison_conditions.py
271 272 273 274 275 276 277 |
|
Condition to check if the left value matches a regex pattern.
condition
Condition
Bases: BaseModel
, ABC
Source code in luthien_control/control_policy/conditions/condition.py
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
|
Abstract base class for conditions in control policies.
Conditions are used to evaluate whether a policy should be applied based on the current transaction.
from_serialized(serialized)
classmethod
Source code in luthien_control/control_policy/conditions/condition.py
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
|
Construct a condition from a serialized configuration.
This method acts as a dispatcher. It looks up the concrete condition class based on the 'type' field in the config and delegates to its from_serialized method.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
serialized
|
SerializableDict
|
The condition-specific configuration dictionary. It must contain a 'type' key that maps to a registered condition type. |
required |
Returns:
Type | Description |
---|---|
Condition
|
An instance of the concrete condition class. |
Raises:
Type | Description |
---|---|
ValueError
|
If the 'type' key is missing in config or the type is not registered. |
serialize()
Source code in luthien_control/control_policy/conditions/condition.py
24 25 26 27 28 |
|
Serialize using Pydantic model_dump through SerializableDict validation.
not_cond
NotCondition
Bases: Condition
Source code in luthien_control/control_policy/conditions/not_cond.py
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
serialize_cond(value)
Source code in luthien_control/control_policy/conditions/not_cond.py
13 14 15 16 |
|
Custom serializer for cond field.
validate_cond(value)
classmethod
Source code in luthien_control/control_policy/conditions/not_cond.py
18 19 20 21 22 23 24 |
|
Custom validator to deserialize condition from dict.
util
get_transaction_value(transaction, path)
Source code in luthien_control/control_policy/conditions/util.py
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
|
Get a value from the transaction using a path.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
transaction
|
Transaction
|
The transaction. |
required |
path
|
str
|
The path to the value e.g. "request.payload.model", "response.payload.choices", "data.user_id". |
required |
Returns:
Type | Description |
---|---|
Any
|
The value at the path. |
Raises:
Type | Description |
---|---|
ValueError
|
If the path is invalid or the value cannot be accessed. |
value_resolvers
StaticValue
Bases: ValueResolver
Source code in luthien_control/control_policy/conditions/value_resolvers.py
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
|
A static value that doesn't depend on the transaction.
__eq__(other)
Source code in luthien_control/control_policy/conditions/value_resolvers.py
66 67 68 |
|
Check equality with another StaticValue.
resolve(transaction)
Source code in luthien_control/control_policy/conditions/value_resolvers.py
59 60 61 |
|
Return the static value.
TransactionPath
Bases: ValueResolver
Source code in luthien_control/control_policy/conditions/value_resolvers.py
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
|
A value resolver that extracts a value from a transaction using a path.
__eq__(other)
Source code in luthien_control/control_policy/conditions/value_resolvers.py
89 90 91 |
|
Check equality with another TransactionPath.
resolve(transaction)
Source code in luthien_control/control_policy/conditions/value_resolvers.py
79 80 81 82 83 84 |
|
Resolve the value from the transaction using the path.
ValueResolver
Bases: BaseModel
, ABC
Source code in luthien_control/control_policy/conditions/value_resolvers.py
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
|
Abstract base class for resolving values from transactions.
from_serialized(serialized)
classmethod
Source code in luthien_control/control_policy/conditions/value_resolvers.py
35 36 37 38 39 40 41 42 43 44 45 46 |
|
Create a value resolver from a serialized dictionary.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
serialized
|
SerializableDict
|
The serialized representation |
required |
Returns:
Type | Description |
---|---|
ValueResolver
|
A ValueResolver instance |
resolve(transaction)
abstractmethod
Source code in luthien_control/control_policy/conditions/value_resolvers.py
18 19 20 21 22 23 24 25 26 27 28 29 |
|
Resolve and return a value from the transaction.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
transaction
|
Transaction
|
The transaction to resolve the value from |
required |
Returns:
Type | Description |
---|---|
Any
|
The resolved value |
serialize()
Source code in luthien_control/control_policy/conditions/value_resolvers.py
31 32 33 |
|
Serialize using Pydantic model_dump through SerializableDict validation.
auto_resolve_value(value)
Source code in luthien_control/control_policy/conditions/value_resolvers.py
123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
|
Automatically convert a value to an appropriate ValueResolver.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
value
|
Any
|
Either a static value or a ValueResolver instance |
required |
Returns:
Type | Description |
---|---|
ValueResolver
|
A ValueResolver instance |
create_value_resolver(serialized)
Source code in luthien_control/control_policy/conditions/value_resolvers.py
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
|
Create a value resolver from serialized data.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
serialized
|
SerializableDict
|
The serialized value resolver data |
required |
Returns:
Type | Description |
---|---|
ValueResolver
|
A ValueResolver instance |
Raises:
Type | Description |
---|---|
ValueError
|
If the resolver type is unknown |
KeyError
|
If the type field is missing |
path(transaction_path)
Source code in luthien_control/control_policy/conditions/value_resolvers.py
139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
|
Convenience function to create a TransactionPath.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
transaction_path
|
str
|
The path to the value in the transaction |
required |
Returns:
Type | Description |
---|---|
TransactionPath
|
A TransactionPath instance |
Example
path("request.payload.model")
control_policy
ControlPolicy
Bases: BaseModel
, ABC
Source code in luthien_control/control_policy/control_policy.py
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
|
Abstract Base Class defining the interface for a processing step.
Attributes:
Name | Type | Description |
---|---|---|
name |
Optional[str]
|
An optional name for the policy instance.
Subclasses are expected to set this, often in their |
__init__(**data)
Source code in luthien_control/control_policy/control_policy.py
49 50 51 52 53 54 55 56 57 58 59 60 |
|
Initializes the ControlPolicy.
This is an abstract base class, and this constructor typically handles common initialization or can be overridden by subclasses.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
**data
|
Any
|
Arbitrary keyword arguments that subclasses might use. |
{}
|
apply(transaction, container, session)
abstractmethod
async
Source code in luthien_control/control_policy/control_policy.py
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
|
Apply the policy to the transaction using provided dependencies.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
transaction
|
Transaction
|
The current transaction. |
required |
container
|
DependencyContainer
|
The dependency injection container. |
required |
session
|
AsyncSession
|
The database session for the current request. We include this separately because it's request-scoped rather than application-scoped. |
required |
Returns:
Type | Description |
---|---|
Transaction
|
The potentially modified transaction. |
Raises:
Type | Description |
---|---|
Exception
|
Processors may raise exceptions to halt the processing flow. |
from_serialized(config)
classmethod
Source code in luthien_control/control_policy/control_policy.py
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
|
Construct a policy from a serialized configuration and optional dependencies.
This method acts as a dispatcher. It looks up the concrete policy class based on the 'type' field in the config and delegates to its from_serialized method.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
config
|
SerializableDict
|
The policy-specific configuration dictionary. It must contain a 'type' key that maps to a registered policy type. |
required |
**kwargs
|
Additional dependencies needed for instantiation, passed to the concrete policy's from_serialized method. |
required |
Returns:
Type | Description |
---|---|
PolicyT
|
An instance of the concrete policy class. |
Raises:
Type | Description |
---|---|
ValueError
|
If the 'type' key is missing in config or the type is not registered. |
get_policy_type_name()
classmethod
Source code in luthien_control/control_policy/control_policy.py
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
|
Get the canonical policy type name for serialization.
By default, this looks up the class in the registry to get its registered name. Subclasses can override this if they need custom behavior.
Returns:
Type | Description |
---|---|
str
|
The policy type name used in serialization. |
serialize()
Source code in luthien_control/control_policy/control_policy.py
86 87 88 89 90 91 |
|
Serialize using Pydantic model_dump through SerializableDict validation.
exceptions
ApiKeyNotFoundError
Bases: ControlPolicyError
Source code in luthien_control/control_policy/exceptions.py
62 63 64 65 66 67 68 69 70 71 72 73 |
|
Exception raised when the API key is not found in the settings.
__init__(detail, status_code=500)
Source code in luthien_control/control_policy/exceptions.py
65 66 67 68 69 70 71 72 73 |
|
Initializes the ApiKeyNotFoundError.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
detail
|
str
|
A detailed error message explaining the missing API key. |
required |
status_code
|
int
|
The HTTP status code to associate with this error. Defaults to 500 (Internal Server Error). |
500
|
ClientAuthenticationError
Bases: ControlPolicyError
Source code in luthien_control/control_policy/exceptions.py
82 83 84 85 86 87 88 89 90 91 92 93 94 |
|
Exception raised when client API key authentication fails.
__init__(detail, status_code=401)
Source code in luthien_control/control_policy/exceptions.py
85 86 87 88 89 90 91 92 93 94 |
|
Initializes the ClientAuthenticationError.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
detail
|
str
|
A detailed error message explaining the authentication failure. |
required |
status_code
|
int
|
The HTTP status code to associate with this error. Defaults to 401 (Unauthorized). |
401
|
ClientAuthenticationNotFoundError
Bases: ControlPolicyError
Source code in luthien_control/control_policy/exceptions.py
97 98 99 100 101 102 103 104 105 106 107 108 109 |
|
Exception raised when the client API key is not found in the request.
__init__(detail, status_code=401)
Source code in luthien_control/control_policy/exceptions.py
100 101 102 103 104 105 106 107 108 109 |
|
Initializes the ClientAuthenticationNotFoundError.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
detail
|
str
|
A detailed error message explaining why the key was not found. |
required |
status_code
|
int
|
The HTTP status code to associate with this error. Defaults to 401 (Unauthorized). |
401
|
ControlPolicyError
Bases: LuthienException
Source code in luthien_control/control_policy/exceptions.py
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
Base exception for all control policy errors.
Attributes:
Name | Type | Description |
---|---|---|
policy_name |
Optional[str]
|
The name of the policy where the error occurred, if specified. |
status_code |
Optional[int]
|
An HTTP status code associated with this error, if specified. |
detail |
Optional[str]
|
A detailed error message. If not provided directly during initialization but other arguments are, the first positional argument is used as the detail. |
__init__(*args, policy_name=None, status_code=None, detail=None)
Source code in luthien_control/control_policy/exceptions.py
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
Initializes the ControlPolicyError.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
*args
|
Arguments passed to the base Exception class. |
()
|
|
policy_name
|
Optional[str]
|
The name of the policy where the error occurred. |
None
|
status_code
|
Optional[int]
|
An HTTP status code associated with this error. |
None
|
detail
|
Optional[str]
|
A detailed error message. If not provided and |
None
|
LeakedApiKeyError
Bases: ControlPolicyError
Source code in luthien_control/control_policy/exceptions.py
112 113 114 115 116 117 118 119 120 121 122 123 124 |
|
Exception raised when a leaked API key is detected.
__init__(detail, status_code=403)
Source code in luthien_control/control_policy/exceptions.py
115 116 117 118 119 120 121 122 123 124 |
|
Initializes the LeakedApiKeyError.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
detail
|
str
|
A detailed error message explaining the leaked key detection. |
required |
status_code
|
int
|
The HTTP status code to associate with this error. Defaults to 403 (Forbidden). |
403
|
NoRequestError
Bases: ControlPolicyError
Source code in luthien_control/control_policy/exceptions.py
76 77 78 79 |
|
Exception raised when the request object is not found in the context.
PolicyLoadError
Bases: ValueError
, ControlPolicyError
Source code in luthien_control/control_policy/exceptions.py
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
|
Custom exception for errors during policy loading/instantiation.
__init__(*args, policy_name=None, status_code=None, detail=None)
Source code in luthien_control/control_policy/exceptions.py
43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
|
Initializes the PolicyLoadError.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
*args
|
Arguments passed to the base Exception class. |
()
|
|
policy_name
|
Optional[str]
|
The name of the policy that failed to load. |
None
|
status_code
|
Optional[int]
|
An HTTP status code associated with this error. |
None
|
detail
|
Optional[str]
|
A detailed error message. If not provided and |
None
|
leaked_api_key_detection
Control Policy for detecting leaked API keys in LLM message content.
This policy inspects the 'messages' field in request bodies to prevent sensitive API keys from being sent to language models.
LeakedApiKeyDetectionPolicy
Bases: ControlPolicy
Source code in luthien_control/control_policy/leaked_api_key_detection.py
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
|
Detects API keys that might be leaked in message content sent to LLMs.
This policy scans message content for patterns matching common API key formats to prevent accidental exposure of sensitive credentials to language models.
apply(transaction, container, session)
async
Source code in luthien_control/control_policy/leaked_api_key_detection.py
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
|
Checks message content for potentially leaked API keys.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
transaction
|
Transaction
|
The current transaction. |
required |
container
|
DependencyContainer
|
The application dependency container. |
required |
session
|
AsyncSession
|
An active SQLAlchemy AsyncSession. |
required |
Returns:
Type | Description |
---|---|
Transaction
|
The transaction, potentially with an error response set. |
Raises:
Type | Description |
---|---|
NoRequestError
|
If the request is not found in the transaction. |
LeakedApiKeyError
|
If a potential API key is detected in message content. |
compile_patterns()
Source code in luthien_control/control_policy/leaked_api_key_detection.py
46 47 48 49 50 |
|
Compile regex patterns after validation.
validate_patterns(value)
classmethod
Source code in luthien_control/control_policy/leaked_api_key_detection.py
38 39 40 41 42 43 44 |
|
Handle patterns validation and fallback to defaults for empty lists.
loader
load_policy(serialized_policy)
Source code in luthien_control/control_policy/loader.py
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
|
Loads a ControlPolicy instance from a dictionary containing its name and config, injecting required dependencies.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
serialized_policy
|
SerializedPolicy
|
A SerializedPolicy object. |
required |
Returns:
Type | Description |
---|---|
ControlPolicy
|
An instantiated ControlPolicy object. |
Raises:
Type | Description |
---|---|
PolicyLoadError
|
If the policy name is unknown, data is missing/malformed, or a required dependency is not provided. |
Exception
|
Potentially from the policy's from_serialized method if config is invalid. |
load_policy_from_file(filepath)
Source code in luthien_control/control_policy/loader.py
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
|
Load a policy configuration from a file and instantiate it using the control_policy loader.
model_name_replacement
ModelNameReplacementPolicy
Bases: ControlPolicy
Source code in luthien_control/control_policy/model_name_replacement.py
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
|
Replaces model names in requests based on a configured mapping.
This policy allows clients to use fake model names that will be replaced with real model names before the request is sent to the backend. This is useful for services like Cursor that assume model strings that match known models must route through specific endpoints.
apply(transaction, container, session)
async
Source code in luthien_control/control_policy/model_name_replacement.py
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
|
Replaces the model name in the request payload based on the configured mapping.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
transaction
|
Transaction
|
The current transaction. |
required |
container
|
DependencyContainer
|
The application dependency container. |
required |
session
|
AsyncSession
|
An active SQLAlchemy AsyncSession (unused). |
required |
Returns:
Type | Description |
---|---|
Transaction
|
The potentially modified transaction. |
Raises:
Type | Description |
---|---|
NoRequestError
|
If no request is found in the transaction. |
noop_policy
NoopPolicy
Bases: ControlPolicy
Source code in luthien_control/control_policy/noop_policy.py
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
A policy that does nothing.
This is the simplest possible policy implementation. It passes through the transaction unchanged and has no policy-specific configuration beyond its name.
apply(transaction, container, session)
async
Source code in luthien_control/control_policy/noop_policy.py
21 22 23 24 25 |
|
Simply returns the transaction unchanged.
send_backend_request
SendBackendRequestPolicy
Bases: ControlPolicy
Source code in luthien_control/control_policy/send_backend_request.py
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
|
Policy responsible for sending the chat completions request to the OpenAI-compatible backend using the OpenAI SDK and storing the structured response.
Attributes:
Name | Type | Description |
---|---|---|
name |
str
|
The name of this policy instance, used for logging and identification. It defaults to the class name if not provided during initialization. |
logger |
Logger
|
The logger instance for this policy. |
apply(transaction, container, session)
async
Source code in luthien_control/control_policy/send_backend_request.py
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
|
Sends the chat completions request to the OpenAI-compatible backend using the OpenAI SDK.
This policy uses the OpenAI SDK to send the structured chat completions request from transaction.request.payload to the backend API endpoint. The response is stored as a structured OpenAIChatCompletionsResponse in transaction.response.payload.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
transaction
|
Transaction
|
The current transaction, containing the request payload to be sent. |
required |
container
|
DependencyContainer
|
The application dependency container, providing settings and OpenAI client. |
required |
session
|
AsyncSession
|
An active SQLAlchemy AsyncSession. (Unused by this policy but required by the interface). |
required |
Returns:
Type | Description |
---|---|
Transaction
|
The Transaction, updated with transaction.response.payload containing the |
Transaction
|
OpenAIChatCompletionsResponse from the backend. |
Raises:
Type | Description |
---|---|
ValueError
|
If backend URL or API key is not configured. |
APIError
|
For API-related errors from the OpenAI backend. |
APITimeoutError
|
If the request to the backend times out. |
APIConnectionError
|
For network-related issues during the backend request. |
Exception
|
For any other unexpected errors during request execution. |
serial_policy
SerialPolicy
Bases: ControlPolicy
Source code in luthien_control/control_policy/serial_policy.py
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
|
A Control Policy that applies an ordered sequence of other policies.
Policies are applied sequentially. If any policy raises an exception, the execution stops, and the exception propagates.
Attributes:
Name | Type | Description |
---|---|---|
policies |
Sequence[ControlPolicy]
|
The ordered sequence of ControlPolicy instances that this policy will apply. |
logger |
Logger
|
The logger instance for this policy. |
name |
str
|
The name of this policy instance, used for logging and identification. |
__repr__()
Source code in luthien_control/control_policy/serial_policy.py
78 79 80 81 82 83 |
|
Provides a developer-friendly representation.
apply(transaction, container, session)
async
Source code in luthien_control/control_policy/serial_policy.py
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
|
Applies the contained policies sequentially to the transaction. Requires the DependencyContainer and an active SQLAlchemy AsyncSession.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
transaction
|
Transaction
|
The current transaction. |
required |
container
|
DependencyContainer
|
The application dependency container. |
required |
session
|
AsyncSession
|
An active SQLAlchemy AsyncSession, passed to member policies. |
required |
Returns:
Type | Description |
---|---|
Transaction
|
The transaction after all contained policies have been applied. |
Raises:
Type | Description |
---|---|
Exception
|
Propagates any exception raised by a contained policy. |
from_serialized(config)
classmethod
Source code in luthien_control/control_policy/serial_policy.py
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
|
Constructs a SerialPolicy from serialized data, loading member policies.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
config
|
SerializableDict
|
The serialized configuration dictionary. Expects a 'policies' key containing a list of dictionaries, each with 'type' and 'config'. |
required |
Returns:
Type | Description |
---|---|
SerialPolicy
|
An instance of SerialPolicy. |
Raises:
Type | Description |
---|---|
PolicyLoadError
|
If 'policies' key is missing, not a list, or if loading a member policy fails. |
serialization
SerializedPolicy
dataclass
Source code in luthien_control/control_policy/serialization.py
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
|
Represents the serialized form of a ControlPolicy.
This structure is used to store and transfer policy configurations. The 'type' field identifies the specific policy class, and the 'config' field contains the parameters needed to reconstruct that policy instance.
Attributes:
Name | Type | Description |
---|---|---|
type |
str
|
The registered name of the policy type (e.g., "AddApiKeyHeader"). |
config |
SerializableDict
|
A dictionary containing the configuration parameters for the policy instance. |
safe_model_dump(model)
Source code in luthien_control/control_policy/serialization.py
17 18 19 20 |
|
Safely dump a Pydantic model through SerializableDict validation.
safe_model_validate(model_class, data)
Source code in luthien_control/control_policy/serialization.py
26 27 28 29 |
|
Safely validate data through SerializableDict before creating model.
set_backend_policy
SetBackendPolicy
Bases: ControlPolicy
Source code in luthien_control/control_policy/set_backend_policy.py
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
A policy that sets the backend URL for the transaction.
core
dependencies
get_db_session(dependencies=Depends(get_dependencies))
async
Source code in luthien_control/core/dependencies.py
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
|
FastAPI dependency to get an async database session using the container's factory.
get_dependencies(request)
Source code in luthien_control/core/dependencies.py
21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
Dependency to retrieve the DependencyContainer from application state.
get_main_control_policy(dependencies=Depends(get_dependencies))
async
Source code in luthien_control/core/dependencies.py
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
|
Dependency to load and provide the main ControlPolicy instance.
Uses the DependencyContainer to access settings, http_client, and a database session.
initialize_app_dependencies(app_settings)
async
Source code in luthien_control/core/dependencies.py
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
|
Initialize and configure core application dependencies.
This function sets up essential services required by the application, including an HTTP client and a database connection pool. It encapsulates the creation and configuration of these dependencies into a DependencyContainer instance.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
app_settings
|
Settings
|
The application settings instance. |
required |
Returns:
Type | Description |
---|---|
DependencyContainer
|
A DependencyContainer instance populated with initialized dependencies. |
Raises:
Type | Description |
---|---|
RuntimeError
|
If initialization of the HTTP client or database engine fails. |
dependency_container
DependencyContainer
Source code in luthien_control/core/dependency_container.py
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
|
Holds shared dependencies for the application.
This class is responsible for holding all shared dependencies for the application. It is used to inject dependencies into the application and to make it easier to mock dependencies for testing.
__init__(settings, http_client, db_session_factory)
Source code in luthien_control/core/dependency_container.py
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
Initializes the container.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
settings
|
Settings
|
Application settings. |
required |
http_client
|
AsyncClient
|
Shared asynchronous HTTP client. |
required |
db_session_factory
|
Callable[[], AsyncContextManager[AsyncSession]]
|
A factory function that returns an async context manager yielding an SQLAlchemy AsyncSession. |
required |
create_openai_client(base_url, api_key)
Source code in luthien_control/core/dependency_container.py
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
|
Creates an OpenAI client for the specified backend URL and API key.
We include this factory here for the sake of consistency with other external dependencies. By maintaining all external dependencies in one place, we can easily mock them for testing and keep track of which parts of the application have external dependencies.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
base_url
|
str
|
The base URL for the OpenAI-compatible API endpoint. |
required |
api_key
|
str
|
The API key for authentication. |
required |
Returns:
Type | Description |
---|---|
AsyncOpenAI
|
An configured OpenAI AsyncClient instance. |
Raises:
Type | Description |
---|---|
ValueError
|
If the base_url is missing or doesn't have a valid protocol. |
generic_events
Generic event system with type-safe event dispatching.
Event
Bases: Generic[T]
Source code in luthien_control/core/generic_events.py
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
|
A generic event that maintains a named registry of typed event listeners to be dispatched on demand.
Typical usage
start_policy_event = LuthienEventType("start_policy") event: Event[dict] = Eventdict data = {"foo": "bar"} def listener_1(event_type, data): print(f"Listener 1 received event: {event_type} {data}") def listener_2(event_type, data): print(f"Listener 2 received event: {event_type} {data}")
event.register("listener_1", listener_1) event.register("listener_2", listener_2) event.dispatch(data) # Listener 1 and 2 will receive the event event.unregister("listener_1") event.dispatch(data) # Listener 2 will receive the event
Type Parameters
T: The type of data that will be passed to event listeners
property
Return the number of registered listeners.
listener_count
property
Return the number of registered listeners.
__init__(event_type)
Source code in luthien_control/core/generic_events.py
38 39 40 41 42 43 44 45 |
|
Initialize an event with no registered listeners.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
event_type
|
str
|
The type of event this observer is for |
required |
dispatch(data)
Source code in luthien_control/core/generic_events.py
67 68 69 70 71 72 73 74 75 76 77 |
|
Dispatch the event to all registered observers.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data
|
T
|
The data of type T to pass to all listeners |
required |
get_listeners()
Source code in luthien_control/core/generic_events.py
84 85 86 87 88 89 90 |
|
Return a copy of the registered listeners dictionary.
Returns:
Type | Description |
---|---|
Dict[str, EventListener[T]]
|
A copy of the listeners registry |
register(name, listener)
Source code in luthien_control/core/generic_events.py
47 48 49 50 51 52 53 54 |
|
Register a named observer.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
name
|
str
|
Unique identifier for this listener |
required |
listener
|
EventListener[T]
|
Callable that accepts an argument of type T |
required |
unregister(name)
Source code in luthien_control/core/generic_events.py
56 57 58 59 60 61 62 63 64 65 |
|
Remove a registered observer by name.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
name
|
str
|
The name of the listener to remove |
required |
Raises:
Type | Description |
---|---|
KeyError
|
If no listener with the given name exists |
logging
setup_logging()
Source code in luthien_control/core/logging.py
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
|
Configures logging for the application.
Reads the desired log level from the LOG_LEVEL environment variable. Defaults to INFO if not set or invalid. Sets a standard format and directs logs to stderr. Sets louder libraries to WARNING level. Optionally configures Loki handler if LOKI_URL is set.
request
Request
Bases: DeepEventedModel
Source code in luthien_control/core/request.py
7 8 9 10 11 12 |
|
A request to the Luthien Control API.
response
Response
Bases: DeepEventedModel
Source code in luthien_control/core/response.py
9 10 11 12 13 |
|
A response from the Luthien Control API.
tracked_context
TrackedContext module with explicit mutation API and event tracking.
TrackedContext
Source code in luthien_control/core/tracked_context/tracked_context.py
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
|
Transaction context with explicit mutation API and event tracking.
property
Get a copy of the tracked request.
request
property
Get a copy of the tracked request.
property
Get a copy of the tracked response.
response
property
Get a copy of the tracked response.
property
Get transaction ID.
transaction_id
property
Get transaction ID.
__init__(transaction_id=None)
Source code in luthien_control/core/tracked_context/tracked_context.py
46 47 48 49 50 51 52 |
|
Initialize tracked context.
get_all_data()
Source code in luthien_control/core/tracked_context/tracked_context.py
169 170 171 |
|
Get copy of all data.
get_data(key, default=None)
Source code in luthien_control/core/tracked_context/tracked_context.py
153 154 155 |
|
Get data value.
set_data(key, value)
Source code in luthien_control/core/tracked_context/tracked_context.py
157 158 159 160 161 162 163 164 165 166 167 |
|
Set data value.
update_request(method=None, url=None, headers=None, content=None, from_scratch=False, preserve_existing_headers=True)
Source code in luthien_control/core/tracked_context/tracked_context.py
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
|
Create or set the request.
update_response(status_code=None, content=None, headers=None, from_scratch=False, preserve_existing_headers=True)
Source code in luthien_control/core/tracked_context/tracked_context.py
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
|
Update the response.
get_tx_value(tracked_context, path)
Source code in luthien_control/core/tracked_context/util.py
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
|
Get a value from the tracked context using a path.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
tracked_context
|
TrackedContext
|
The tracked context. |
required |
path
|
str
|
The path to the value e.g. "request.headers.user-agent", "response.status_code", "data.user_id". |
required |
Returns:
Type | Description |
---|---|
Any
|
The value at the path. |
Raises:
Type | Description |
---|---|
ValueError
|
If the path is invalid or the value cannot be accessed. |
tracked_context
TrackedContext with explicit mutation API and event tracking.
MutationEventPayload
dataclass
Source code in luthien_control/core/tracked_context/tracked_context.py
30 31 32 33 34 35 36 |
|
Record of an explicit mutation.
TrackedContext
Source code in luthien_control/core/tracked_context/tracked_context.py
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
|
Transaction context with explicit mutation API and event tracking.
property
Get a copy of the tracked request.
request
property
Get a copy of the tracked request.
property
Get a copy of the tracked response.
response
property
Get a copy of the tracked response.
property
Get transaction ID.
transaction_id
property
Get transaction ID.
__init__(transaction_id=None)
Source code in luthien_control/core/tracked_context/tracked_context.py
46 47 48 49 50 51 52 |
|
Initialize tracked context.
get_all_data()
Source code in luthien_control/core/tracked_context/tracked_context.py
169 170 171 |
|
Get copy of all data.
get_data(key, default=None)
Source code in luthien_control/core/tracked_context/tracked_context.py
153 154 155 |
|
Get data value.
set_data(key, value)
Source code in luthien_control/core/tracked_context/tracked_context.py
157 158 159 160 161 162 163 164 165 166 167 |
|
Set data value.
update_request(method=None, url=None, headers=None, content=None, from_scratch=False, preserve_existing_headers=True)
Source code in luthien_control/core/tracked_context/tracked_context.py
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
|
Create or set the request.
update_response(status_code=None, content=None, headers=None, from_scratch=False, preserve_existing_headers=True)
Source code in luthien_control/core/tracked_context/tracked_context.py
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
|
Update the response.
util
Utilities for working with TrackedContext.
get_tx_value(tracked_context, path)
Source code in luthien_control/core/tracked_context/util.py
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
|
Get a value from the tracked context using a path.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
tracked_context
|
TrackedContext
|
The tracked context. |
required |
path
|
str
|
The path to the value e.g. "request.headers.user-agent", "response.status_code", "data.user_id". |
required |
Returns:
Type | Description |
---|---|
Any
|
The value at the path. |
Raises:
Type | Description |
---|---|
ValueError
|
If the path is invalid or the value cannot be accessed. |
transaction
Transaction
Bases: DeepEventedModel
Source code in luthien_control/core/transaction.py
12 13 14 15 16 17 18 |
|
A transaction between the Luthien Control API and the client.
transaction_context
TransactionContext
dataclass
Source code in luthien_control/core/transaction_context.py
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
Holds the state for a single transaction through the proxy.
Attributes:
Name | Type | Description |
---|---|---|
transaction_id |
UUID
|
A unique identifier for the transaction. |
request |
Optional[Request]
|
The incoming HTTP request object. |
response |
Optional[Response]
|
The outgoing HTTP response object. |
data |
Dict[str, Any]
|
A general-purpose dictionary for policies to store and share information related to this transaction. |
get_tx_value(transaction_context, path)
Source code in luthien_control/core/transaction_context.py
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
|
Get a value from the transaction context using a path.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
transaction_context
|
TransactionContext
|
The transaction context. |
required |
path
|
str
|
The path to the value e.g. "request.headers.user-agent", "response.status_code", "data.user_id". |
required |
Returns:
Type | Description |
---|---|
Any
|
The value at the path. |
Raises:
Type | Description |
---|---|
ValueError
|
If the path is invalid or the value cannot be accessed. |
TypeError
|
If the transaction_id is not a UUID. |
custom_openapi_schema
create_custom_openapi(app)
Source code in luthien_control/custom_openapi_schema.py
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
|
Generate a custom OpenAPI schema for the FastAPI application.
This function retrieves the default schema and modifies it, specifically
to set allowReserved=True
for the full_path
path parameter used
in proxy routes. This is necessary for correctly handling URLs containing
reserved characters within that path segment.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
app
|
FastAPI
|
The FastAPI application instance. |
required |
Returns:
Type | Description |
---|---|
The modified OpenAPI schema dictionary. |
db
Database models and session management.
ControlPolicy
Bases: SQLModel
Source code in luthien_control/db/sqlmodel_models.py
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
|
class-attribute
instance-attribute
Database model for storing control policy configurations.
__tablename__ = 'policies'
class-attribute
instance-attribute
Database model for storing control policy configurations.
validate_timestamps(values)
classmethod
Source code in luthien_control/db/sqlmodel_models.py
78 79 80 81 82 83 84 |
|
Ensure updated_at is always set/updated.
LuthienLog
Bases: SQLModel
Source code in luthien_control/db/sqlmodel_models.py
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
|
Represents a log entry in the Luthien logging system using SQLModel.
Attributes:
Name | Type | Description |
---|---|---|
id |
Optional[int]
|
Unique identifier for the log entry (primary key). |
transaction_id |
str
|
Identifier to group related log entries. |
datetime |
NaiveDatetime
|
Timestamp indicating when the log entry was generated (timezone-aware). |
data |
Optional[dict[str, Any]]
|
JSON blob containing the primary logged data. |
datatype |
str
|
String identifier for the nature and schema of 'data'. |
notes |
Optional[dict[str, Any]]
|
JSON blob for additional contextual information. |
__init__(**data)
Source code in luthien_control/db/sqlmodel_models.py
113 114 115 116 117 118 119 |
|
Override init to ensure datetime is converted to NaiveDatetime.
client_api_key_crud
create_api_key(session, api_key)
async
Source code in luthien_control/db/client_api_key_crud.py
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
|
Create a new API key in the database.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
session
|
AsyncSession
|
The database session |
required |
api_key
|
ClientApiKey
|
The API key to create |
required |
Returns:
Type | Description |
---|---|
ClientApiKey
|
The created API key with updated ID |
Raises:
Type | Description |
---|---|
LuthienDBIntegrityError
|
If a constraint violation occurs |
LuthienDBTransactionError
|
If the transaction fails |
LuthienDBOperationError
|
For other database errors |
get_api_key_by_value(session, key_value)
async
Source code in luthien_control/db/client_api_key_crud.py
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
|
Get an active API key by its value.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
session
|
AsyncSession
|
The database session |
required |
key_value
|
str
|
The value of the API key to retrieve |
required |
Returns:
Type | Description |
---|---|
ClientApiKey
|
The API key |
Raises:
Type | Description |
---|---|
LuthienDBQueryError
|
If the API key is not found or if the query execution fails |
LuthienDBOperationError
|
For unexpected errors during lookup |
list_api_keys(session, active_only=False)
async
Source code in luthien_control/db/client_api_key_crud.py
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
|
Get a list of all API keys.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
session
|
AsyncSession
|
The database session |
required |
active_only
|
bool
|
If True, only return active API keys |
False
|
Returns:
Type | Description |
---|---|
List[ClientApiKey]
|
A list of API keys |
Raises:
Type | Description |
---|---|
LuthienDBQueryError
|
If the query execution fails |
update_api_key(session, key_id, api_key_update)
async
Source code in luthien_control/db/client_api_key_crud.py
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
|
Update an existing API key.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
session
|
AsyncSession
|
The database session |
required |
key_id
|
int
|
The ID of the API key to update |
required |
api_key_update
|
ClientApiKey
|
The updated API key data |
required |
Returns:
Type | Description |
---|---|
ClientApiKey
|
The updated API key |
Raises:
Type | Description |
---|---|
LuthienDBQueryError
|
If the API key is not found |
LuthienDBIntegrityError
|
If a constraint violation occurs |
LuthienDBTransactionError
|
If the transaction fails |
LuthienDBOperationError
|
For other database errors |
control_policy_crud
get_policy_by_name(session, name)
async
Source code in luthien_control/db/control_policy_crud.py
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
|
Get a policy by its name.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
session
|
AsyncSession
|
The database session |
required |
name
|
str
|
The name of the policy to retrieve |
required |
Returns:
Type | Description |
---|---|
ControlPolicy
|
The policy |
Raises:
Type | Description |
---|---|
LuthienDBQueryError
|
If the policy is not found or if the query execution fails |
LuthienDBOperationError
|
For unexpected errors during lookup |
get_policy_config_by_name(session, name)
async
Source code in luthien_control/db/control_policy_crud.py
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
|
Get a policy configuration by its name, regardless of its active status.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
session
|
AsyncSession
|
The database session |
required |
name
|
str
|
The name of the policy to retrieve |
required |
Returns:
Type | Description |
---|---|
ControlPolicy
|
The policy |
Raises:
Type | Description |
---|---|
LuthienDBQueryError
|
If the policy is not found or if the query execution fails |
LuthienDBOperationError
|
For unexpected errors during lookup |
list_policies(session, active_only=False)
async
Source code in luthien_control/db/control_policy_crud.py
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
|
Get a list of all policies.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
session
|
AsyncSession
|
The database session |
required |
active_only
|
bool
|
If True, only return active policies |
False
|
Returns:
Type | Description |
---|---|
List[ControlPolicy]
|
A list of policies |
Raises:
Type | Description |
---|---|
LuthienDBQueryError
|
If the query execution fails |
load_policy_from_db(name, container)
async
Source code in luthien_control/db/control_policy_crud.py
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
|
Load a policy configuration from the database and instantiate it using the control_policy loader.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
name
|
str
|
The name of the policy to load |
required |
container
|
DependencyContainer
|
The dependency container providing access to the database session |
required |
Returns:
Type | Description |
---|---|
ControlPolicy
|
The instantiated policy |
Raises:
Type | Description |
---|---|
LuthienDBQueryError
|
If the database query fails or policy is not found |
LuthienDBOperationError
|
If the policy cannot be instantiated or other database operation errors occur |
save_policy_to_db(session, policy)
async
Source code in luthien_control/db/control_policy_crud.py
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
|
Create a new policy in the database.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
session
|
AsyncSession
|
The database session |
required |
policy
|
ControlPolicy
|
The policy to create |
required |
Returns:
Type | Description |
---|---|
ControlPolicy
|
The created policy with updated ID |
Raises:
Type | Description |
---|---|
LuthienDBIntegrityError
|
If a constraint violation occurs |
LuthienDBTransactionError
|
If the transaction fails |
LuthienDBOperationError
|
For other database errors |
update_policy(session, policy_id, policy_update)
async
Source code in luthien_control/db/control_policy_crud.py
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
|
Update an existing policy.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
session
|
AsyncSession
|
The database session |
required |
policy_id
|
int
|
The ID of the policy to update |
required |
policy_update
|
ControlPolicy
|
The updated policy data |
required |
Returns:
Type | Description |
---|---|
ControlPolicy
|
The updated policy |
Raises:
Type | Description |
---|---|
LuthienDBQueryError
|
If the policy is not found |
LuthienDBIntegrityError
|
If a constraint violation occurs |
LuthienDBTransactionError
|
If the transaction fails |
LuthienDBOperationError
|
For other database errors |
database_async
close_db_engine()
async
Source code in luthien_control/db/database_async.py
116 117 118 119 120 121 122 123 124 125 126 127 128 |
|
Closes the database engine.
create_db_engine()
async
Source code in luthien_control/db/database_async.py
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
|
Creates the asyncpg engine for the application DB. Returns: The asyncpg engine for the application DB.
Raises:
Type | Description |
---|---|
LuthienDBConfigurationError
|
If the database configuration is invalid. |
LuthienDBConnectionError
|
If the database connection fails. |
get_db_session()
async
Source code in luthien_control/db/database_async.py
131 132 133 134 135 136 137 138 139 140 141 142 |
|
Get a SQLAlchemy async session for the database as a context manager.
exceptions
Database-specific exceptions for the Luthien Control project.
LuthienDBIntegrityError
Bases: LuthienDBOperationError
Source code in luthien_control/db/exceptions.py
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
|
Exception raised when a database integrity constraint is violated.
This exception wraps SQLAlchemy's IntegrityError and provides a more specific error type for the Luthien Control project.
__init__(message, original_error=None)
Source code in luthien_control/db/exceptions.py
45 46 47 48 49 50 51 52 53 |
|
Initialize the exception.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
message
|
str
|
A descriptive error message |
required |
original_error
|
Optional[IntegrityError]
|
The original IntegrityError that was raised |
None
|
LuthienDBOperationError
Bases: LuthienDBException
Source code in luthien_control/db/exceptions.py
10 11 12 13 14 15 16 17 |
|
Base exception for database operation errors.
This exception is raised when a database operation fails for any reason. It serves as a base class for more specific database operation errors.
LuthienDBQueryError
Bases: LuthienDBOperationError
Source code in luthien_control/db/exceptions.py
20 21 22 23 24 25 26 |
|
Exception raised when a database query fails.
This exception is raised when a SELECT query fails to execute properly.
LuthienDBTransactionError
Bases: LuthienDBOperationError
Source code in luthien_control/db/exceptions.py
29 30 31 32 33 34 35 |
|
Exception raised when a database transaction fails.
This exception is raised when a transaction (commit, rollback) fails.
luthien_log_crud
count_logs(session, transaction_id=None, datatype=None, start_datetime=None, end_datetime=None)
async
Source code in luthien_control/db/luthien_log_crud.py
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
|
Count logs with optional filtering.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
session
|
AsyncSession
|
The database session |
required |
transaction_id
|
Optional[str]
|
Optional filter by transaction ID |
None
|
datatype
|
Optional[str]
|
Optional filter by datatype |
None
|
start_datetime
|
Optional[datetime]
|
Optional filter for logs after this datetime |
None
|
end_datetime
|
Optional[datetime]
|
Optional filter for logs before this datetime |
None
|
Returns:
Type | Description |
---|---|
int
|
The count of matching logs |
Raises:
Type | Description |
---|---|
LuthienDBQueryError
|
If the query execution fails |
LuthienDBOperationError
|
For unexpected errors |
get_log_by_id(session, log_id)
async
Source code in luthien_control/db/luthien_log_crud.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
|
Get a specific log by its ID.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
session
|
AsyncSession
|
The database session |
required |
log_id
|
int
|
The ID of the log to retrieve |
required |
Returns:
Type | Description |
---|---|
LuthienLog
|
The log entry |
Raises:
Type | Description |
---|---|
LuthienDBQueryError
|
If the log is not found or if the query execution fails |
LuthienDBOperationError
|
For unexpected errors during lookup |
get_unique_datatypes(session)
async
Source code in luthien_control/db/luthien_log_crud.py
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
|
Get a list of unique datatypes from the logs.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
session
|
AsyncSession
|
The database session |
required |
Returns:
Type | Description |
---|---|
List[str]
|
A list of unique datatype values |
Raises:
Type | Description |
---|---|
LuthienDBQueryError
|
If the query execution fails |
LuthienDBOperationError
|
For unexpected errors |
get_unique_transaction_ids(session, limit=100)
async
Source code in luthien_control/db/luthien_log_crud.py
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
|
Get a list of unique transaction IDs from recent logs.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
session
|
AsyncSession
|
The database session |
required |
limit
|
int
|
Maximum number of transaction IDs to return (default: 100) |
100
|
Returns:
Type | Description |
---|---|
List[str]
|
A list of unique transaction ID values |
Raises:
Type | Description |
---|---|
LuthienDBQueryError
|
If the query execution fails |
LuthienDBOperationError
|
For unexpected errors |
list_logs(session, transaction_id=None, datatype=None, limit=100, offset=0, start_datetime=None, end_datetime=None)
async
Source code in luthien_control/db/luthien_log_crud.py
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
|
Get a list of logs with optional filtering.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
session
|
AsyncSession
|
The database session |
required |
transaction_id
|
Optional[str]
|
Optional filter by transaction ID |
None
|
datatype
|
Optional[str]
|
Optional filter by datatype |
None
|
limit
|
int
|
Maximum number of logs to return (default: 100) |
100
|
offset
|
int
|
Number of logs to skip (default: 0) |
0
|
start_datetime
|
Optional[datetime]
|
Optional filter for logs after this datetime |
None
|
end_datetime
|
Optional[datetime]
|
Optional filter for logs before this datetime |
None
|
Returns:
Type | Description |
---|---|
List[LuthienLog]
|
A list of LuthienLog entries |
Raises:
Type | Description |
---|---|
LuthienDBQueryError
|
If the query execution fails |
LuthienDBOperationError
|
For unexpected errors |
naive_datetime
NaiveDatetime
Bases: datetime
Source code in luthien_control/db/naive_datetime.py
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
|
A datetime that automatically strips timezone info.
__get_pydantic_core_schema__(source_type, handler)
classmethod
Source code in luthien_control/db/naive_datetime.py
28 29 30 31 32 33 34 |
|
Pydantic schema for NaiveDatetime.
now(tz=None)
classmethod
Source code in luthien_control/db/naive_datetime.py
22 23 24 25 26 |
|
Create a NaiveDatetime representing the current UTC time (naive).
sqlmodel_models
AdminSession
Bases: SQLModel
Source code in luthien_control/db/sqlmodel_models.py
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
|
Admin session model for managing active sessions.
AdminUser
Bases: SQLModel
Source code in luthien_control/db/sqlmodel_models.py
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
|
Admin user model for authentication and authorization.
ControlPolicy
Bases: SQLModel
Source code in luthien_control/db/sqlmodel_models.py
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
|
class-attribute
instance-attribute
Database model for storing control policy configurations.
__tablename__ = 'policies'
class-attribute
instance-attribute
Database model for storing control policy configurations.
validate_timestamps(values)
classmethod
Source code in luthien_control/db/sqlmodel_models.py
78 79 80 81 82 83 84 |
|
Ensure updated_at is always set/updated.
JsonBOrJson
Bases: TypeDecorator
Source code in luthien_control/db/sqlmodel_models.py
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Represents a JSON type that uses JSONB for PostgreSQL and JSON for other dialects (like SQLite).
This is mostly a hack for unit testing, as SQLite does not support JSONB.
LuthienLog
Bases: SQLModel
Source code in luthien_control/db/sqlmodel_models.py
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
|
Represents a log entry in the Luthien logging system using SQLModel.
Attributes:
Name | Type | Description |
---|---|---|
id |
Optional[int]
|
Unique identifier for the log entry (primary key). |
transaction_id |
str
|
Identifier to group related log entries. |
datetime |
NaiveDatetime
|
Timestamp indicating when the log entry was generated (timezone-aware). |
data |
Optional[dict[str, Any]]
|
JSON blob containing the primary logged data. |
datatype |
str
|
String identifier for the nature and schema of 'data'. |
notes |
Optional[dict[str, Any]]
|
JSON blob for additional contextual information. |
__init__(**data)
Source code in luthien_control/db/sqlmodel_models.py
113 114 115 116 117 118 119 |
|
Override init to ensure datetime is converted to NaiveDatetime.
exceptions
LuthienDBConfigurationError
Bases: LuthienDBException
Source code in luthien_control/exceptions.py
13 14 15 16 |
|
Exception raised when a database configuration is invalid or missing required variables.
LuthienDBConnectionError
Bases: LuthienDBException
Source code in luthien_control/exceptions.py
19 20 21 22 |
|
Exception raised when a connection to the database fails.
LuthienDBException
Bases: LuthienException
Source code in luthien_control/exceptions.py
7 8 9 10 |
|
Base exception for all Luthien DB related errors.
LuthienException
Bases: Exception
Source code in luthien_control/exceptions.py
1 2 3 4 |
|
Base exception for all Luthien errors.
logs
router
get_datatypes(session=Depends(get_db_session))
async
Source code in luthien_control/logs/router.py
151 152 153 154 155 156 157 158 159 160 161 162 163 |
|
Get list of unique datatypes from logs.
get_log(log_id, session=Depends(get_db_session))
async
Source code in luthien_control/logs/router.py
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
|
Get a specific log by ID.
get_logs(session=Depends(get_db_session), transaction_id=Query(None, description='Filter by transaction ID'), datatype=Query(None, description='Filter by datatype'), limit=Query(100, ge=1, le=1000, description='Maximum number of logs to return'), offset=Query(0, ge=0, description='Number of logs to skip'), start_datetime=Query(None, description='Start datetime (ISO format)'), end_datetime=Query(None, description='End datetime (ISO format)'))
async
Source code in luthien_control/logs/router.py
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
|
Get logs with optional filtering and pagination.
Returns:
Type | Description |
---|---|
Dict[str, Any]
|
Dictionary containing logs, pagination info, and metadata |
get_transaction_ids(limit=Query(100, ge=1, le=500, description='Maximum number of transaction IDs to return'), session=Depends(get_db_session))
async
Source code in luthien_control/logs/router.py
166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
|
Get list of unique transaction IDs from recent logs.
logs_ui(request)
async
Source code in luthien_control/logs/router.py
26 27 28 29 |
|
Serve the logs exploration UI.
main
health_check()
async
Source code in luthien_control/main.py
102 103 104 105 106 107 108 109 110 111 112 |
|
Perform a basic health check.
This endpoint can be used to verify that the application is running and responsive.
Returns:
Type | Description |
---|---|
A dictionary indicating the application status. |
lifespan(app)
async
Source code in luthien_control/main.py
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
|
Manage the lifespan of the application resources.
This asynchronous context manager handles the startup and shutdown events of the FastAPI application. It initializes dependencies on startup and ensures they are properly cleaned up on shutdown.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
app
|
FastAPI
|
The FastAPI application instance. |
required |
Yields:
Name | Type | Description |
---|---|---|
None |
After startup procedures are complete, allowing the application to run. |
Raises:
Type | Description |
---|---|
RuntimeError
|
If critical application dependencies fail to initialize during startup. |
read_root()
async
Source code in luthien_control/main.py
123 124 125 126 127 128 129 130 |
|
Provide a simple root endpoint.
Returns:
Type | Description |
---|---|
A welcome message indicating the proxy is running. |
proxy
debugging
Enhanced debugging utilities for the proxy pipeline.
DebugLoggingMiddleware
Bases: BaseHTTPMiddleware
Source code in luthien_control/proxy/debugging.py
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
|
Middleware to add detailed request/response logging for debugging.
create_debug_response(status_code, message, transaction_id, details=None, include_debug_info=True)
Source code in luthien_control/proxy/debugging.py
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
|
Create a detailed error response for debugging.
log_policy_execution(transaction_id, policy_name, status, duration=None, error=None, details=None)
Source code in luthien_control/proxy/debugging.py
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
|
Log policy execution details.
log_transaction_state(transaction_id, stage, details)
Source code in luthien_control/proxy/debugging.py
92 93 94 95 96 97 |
|
Log transaction state at various stages of processing.
orchestration
run_policy_flow(request, main_policy, dependencies, session)
async
Source code in luthien_control/proxy/orchestration.py
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
|
Orchestrates the execution of the main ControlPolicy using injected dependencies. Exceptions raised by policies are expected to be caught by FastAPI exception handlers.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
request
|
Request
|
The incoming FastAPI request. |
required |
main_policy
|
ControlPolicy
|
The main policy instance to execute. |
required |
dependencies
|
DependencyContainer
|
The application's dependency container. |
required |
session
|
AsyncSession
|
The database session for this request. |
required |
Returns:
Type | Description |
---|---|
Response
|
The final FastAPI response. |
server
api_proxy_endpoint(request, full_path=default_path, dependencies=Depends(get_dependencies), main_policy=Depends(get_main_control_policy), session=Depends(get_db_session), payload=default_payload, token=Security(http_bearer_auth))
async
Source code in luthien_control/proxy/server.py
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
|
Main API proxy endpoint using the policy orchestration flow. Handles requests starting with /api/. Uses Dependency Injection Container and provides a DB session.
Authentication Note: This endpoint uses Bearer Token authentication
(Authorization: Bearer
api_proxy_get_endpoint(request, full_path=default_path, dependencies=Depends(get_dependencies), main_policy=Depends(get_main_control_policy), session=Depends(get_db_session), token=Security(http_bearer_auth))
async
Source code in luthien_control/proxy/server.py
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
|
Main API proxy endpoint for GET requests using the policy orchestration flow. Handles GET requests starting with /api/. Uses Dependency Injection Container and provides a DB session.
Authentication Note: This endpoint uses Bearer Token authentication
(Authorization: Bearer
api_proxy_options_handler(full_path=default_path)
async
Source code in luthien_control/proxy/server.py
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
|
Handles OPTIONS requests for the API proxy endpoint, indicating allowed methods.
settings
Settings
Source code in luthien_control/settings.py
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
|
Application configuration settings loaded from environment variables.
property
DSN for connecting to the default 'postgres' db for admin tasks. Raises ValueError if required DB settings are missing.
admin_dsn
property
DSN for connecting to the default 'postgres' db for admin tasks. Raises ValueError if required DB settings are missing.
property
Base DSN without a specific database name. Raises ValueError if required DB settings are missing.
base_dsn
property
Base DSN without a specific database name. Raises ValueError if required DB settings are missing.
dev_mode()
Source code in luthien_control/settings.py
177 178 179 |
|
Returns True if the run mode is 'dev', False otherwise.
get_app_host(default='0.0.0.0')
Source code in luthien_control/settings.py
100 101 102 |
|
Gets the configured app host, defaulting if not set.
get_app_port(default=8000)
Source code in luthien_control/settings.py
104 105 106 |
|
Gets the configured app port, defaulting if not set.
get_app_reload(default=False)
Source code in luthien_control/settings.py
108 109 110 111 112 113 114 115 116 117 118 |
|
Gets the configured app reload, defaulting if not set.
get_backend_url()
Source code in luthien_control/settings.py
30 31 32 33 34 35 36 37 38 |
|
Returns the backend URL as a string, if set.
get_database_url()
Source code in luthien_control/settings.py
40 41 42 |
|
Returns the primary DATABASE_URL, if set.
get_db_dsn(db_name=None)
Source code in luthien_control/settings.py
163 164 165 166 167 168 169 170 171 |
|
Returns the DSN for a specific database name, or the default DB_NAME. Raises ValueError if required DB settings or the target db_name are missing.
get_log_level(default='INFO')
Source code in luthien_control/settings.py
95 96 97 |
|
Gets the configured log level, defaulting if not set.
get_main_db_pool_max_size()
Source code in luthien_control/settings.py
87 88 89 90 91 92 |
|
Returns the maximum pool size for the main DB.
get_main_db_pool_min_size()
Source code in luthien_control/settings.py
80 81 82 83 84 85 |
|
Returns the minimum pool size for the main DB.
get_openai_api_key()
Source code in luthien_control/settings.py
44 45 46 |
|
Returns the OpenAI API key, if set.
get_policy_filepath()
Source code in luthien_control/settings.py
52 53 54 |
|
Returns the path to the policy file, if set.
get_postgres_port()
Source code in luthien_control/settings.py
69 70 71 72 73 74 75 76 77 |
|
Returns the PostgreSQL port as an integer, or None if not set.
get_run_mode()
Source code in luthien_control/settings.py
173 174 175 |
|
Returns the run mode, defaulting to 'prod' if not set.
get_top_level_policy_name()
Source code in luthien_control/settings.py
48 49 50 |
|
Returns the name of the top-level policy instance to load.
utils
DeepEventedModel
Bases: EventedModel
Source code in luthien_control/utils/deep_evented_model.py
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
|
A Pydantic EventedModel that emits a single changed
signal on any change.
This includes changes to top-level fields as well as changes within nested evented containers (like EventedList, EventedDict) or other DeepEventedModel instances.
Attributes:
Name | Type | Description |
---|---|---|
changed |
Signal
|
A signal that is emitted with no arguments when any value in the model or its nested evented children changes. |
backend_call_spec
BackendCallSpec
Bases: BaseModel
Source code in luthien_control/utils/backend_call_spec.py
6 7 8 9 10 11 12 13 14 15 16 17 |
|
A specification for a backend LLM call.
deep_evented_model
DeepEventedModel
Bases: EventedModel
Source code in luthien_control/utils/deep_evented_model.py
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
|
A Pydantic EventedModel that emits a single changed
signal on any change.
This includes changes to top-level fields as well as changes within nested evented containers (like EventedList, EventedDict) or other DeepEventedModel instances.
Attributes:
Name | Type | Description |
---|---|---|
changed |
Signal
|
A signal that is emitted with no arguments when any value in the model or its nested evented children changes. |