-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathheaders.py
More file actions
99 lines (78 loc) · 3.57 KB
/
Copy pathheaders.py
File metadata and controls
99 lines (78 loc) · 3.57 KB
1
2
3
4
5
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
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
import contextvars
from collections.abc import Mapping, Sequence
from httpx import Headers
from uipath.llm_client.settings.base import UiPathAPIConfig
from uipath.llm_client.settings.constants import ApiType, RoutingMode
UIPATH_DEFAULT_REQUEST_HEADERS: dict[str, str] = {
"X-UiPath-LLMGateway-TimeoutSeconds": "295", # server side timeout, default is 10, maximum is 300
"X-UiPath-LLMGateway-AllowFull4xxResponse": "false", # allow full 4xx responses (default is false) — kept false to avoid PII leakage in logs
}
_CAPTURED_RESPONSE_HEADERS: contextvars.ContextVar[dict[str, str] | None] = contextvars.ContextVar(
"_captured_response_headers", default=None
)
_DYNAMIC_REQUEST_HEADERS: contextvars.ContextVar[dict[str, str] | None] = contextvars.ContextVar(
"_dynamic_request_headers", default=None
)
def get_captured_response_headers() -> dict[str, str]:
"""Get response headers captured from the most recent request in this context.
Returns an empty dict if no headers have been captured or if called
outside a capture scope.
"""
return dict(_CAPTURED_RESPONSE_HEADERS.get() or {})
def set_captured_response_headers(
headers: dict[str, str],
) -> contextvars.Token[dict[str, str] | None]:
"""Set captured response headers for the current context."""
return _CAPTURED_RESPONSE_HEADERS.set(headers)
def get_dynamic_request_headers() -> dict[str, str]:
"""Get dynamic headers to be injected into the next outgoing request.
Returns an empty dict if no dynamic headers have been set in this context.
"""
return dict(_DYNAMIC_REQUEST_HEADERS.get() or {})
def set_dynamic_request_headers(
headers: dict[str, str],
) -> contextvars.Token[dict[str, str] | None]:
"""Set headers to be injected into the next outgoing request."""
return _DYNAMIC_REQUEST_HEADERS.set(headers)
def extract_matching_headers(
response_headers: Headers,
prefixes: Sequence[str],
) -> dict[str, str]:
"""Extract response headers whose names match any of the given prefixes (case-insensitive)."""
result: dict[str, str] = {}
for name, value in response_headers.items():
name_lower = name.lower()
for prefix in prefixes:
if name_lower.startswith(prefix.lower()):
result[name] = value
break
return result
def build_routing_headers(
*,
model_name: str | None = None,
byo_connection_id: str | None = None,
api_config: UiPathAPIConfig | None = None,
) -> Mapping[str, str]:
"""Build UiPath LLM Gateway routing headers based on configuration.
Args:
api_config: UiPath API configuration.
model_name: LLM model name (required for normalized API).
byo_connection_id: Bring Your Own connection ID.
Returns:
Headers mapping for routing requests through the gateway.
"""
headers: dict[str, str] = {}
if api_config is not None:
if api_config.routing_mode == RoutingMode.NORMALIZED and model_name is not None:
headers["X-UiPath-LlmGateway-NormalizedApi-ModelName"] = model_name
elif (
api_config.routing_mode == RoutingMode.PASSTHROUGH
and api_config.api_type == ApiType.COMPLETIONS
):
if api_config.api_flavor is not None:
headers["X-UiPath-LlmGateway-ApiFlavor"] = api_config.api_flavor
if api_config.api_version is not None:
headers["X-UiPath-LlmGateway-ApiVersion"] = api_config.api_version
if byo_connection_id is not None:
headers["X-UiPath-LlmGateway-ByoIsConnectionId"] = byo_connection_id
return headers