-
Notifications
You must be signed in to change notification settings - Fork 876
Expand file tree
/
Copy pathconfig_helpers.py
More file actions
154 lines (126 loc) · 4.79 KB
/
Copy pathconfig_helpers.py
File metadata and controls
154 lines (126 loc) · 4.79 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
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
"""Configuration resolution utilities for hierarchical settings."""
import logging
from typing import Any, cast
from src import models
from src.config import settings
from src.schemas import (
MessageConfiguration,
ResolvedConfiguration,
)
logger = logging.getLogger(__name__)
_NONE_OVERRIDE_PATHS: set[tuple[str, ...]] = {
("summary", "custom_instructions"),
}
def deep_update(
base: dict[str, Any],
update: dict[str, Any],
path: tuple[str, ...] = (),
) -> None:
"""
Recursive update of a dictionary.
Skips None values unless None explicitly clears a nullable field.
"""
for key, value in update.items():
current_path = (*path, key)
if value is None:
if current_path in _NONE_OVERRIDE_PATHS:
base[key] = None
continue
if isinstance(value, dict) and key in base and isinstance(base[key], dict):
deep_update(
cast(dict[str, Any], base[key]),
cast(dict[str, Any], value),
current_path,
)
else:
base[key] = value
def normalize_configuration_dict(raw: dict[str, Any]) -> dict[str, Any]:
"""
Normalize a workspace/session/message configuration dict to match the current
`ResolvedConfiguration` schema.
This function exists to preserve backwards compatibility with older clients/tests
that used legacy configuration keys (e.g. `deriver.enabled` or `skip_deriver`).
Behavior:
- If `reasoning.enabled` is not explicitly set, but `deriver.enabled` is present,
`reasoning.enabled` is derived from `deriver.enabled`.
- If `skip_deriver` is explicitly `True`, `reasoning.enabled` is forced to `False`
unless `reasoning.enabled` was already explicitly set.
- Legacy keys are removed from the returned dict to avoid polluting the resolved
configuration with unused fields.
"""
normalized: dict[str, Any] = dict(raw)
reasoning_raw = normalized.get("reasoning")
reasoning_present = "reasoning" in normalized
reasoning: dict[str, Any]
if isinstance(reasoning_raw, dict):
reasoning = dict(cast(dict[str, Any], reasoning_raw))
else:
reasoning = {}
reasoning_enabled_explicit = reasoning.get("enabled") is not None
if not reasoning_enabled_explicit:
deriver_raw = normalized.get("deriver")
deriver: dict[str, Any]
if isinstance(deriver_raw, dict):
deriver = dict(cast(dict[str, Any], deriver_raw))
else:
deriver = {}
if deriver.get("enabled") is not None:
reasoning["enabled"] = bool(deriver["enabled"])
if not reasoning_enabled_explicit and normalized.get("skip_deriver") is True:
reasoning["enabled"] = False
if reasoning_present or reasoning:
normalized["reasoning"] = reasoning
normalized.pop("deriver", None)
normalized.pop("skip_deriver", None)
return normalized
def get_configuration(
message_configuration: MessageConfiguration | None,
session: models.Session | None,
workspace: models.Workspace | None = None,
) -> ResolvedConfiguration:
"""
Resolve session configuration with hierarchical fallback.
Resolution hierarchy:
1. Message configuration
2. Session configuration
3. Workspace configuration
4. Global defaults from settings
Args:
message_configuration: Optional message configuration
session: Optional session model
workspace: Optional workspace model
Returns:
ResolvedConfiguration
"""
# Start with defaults
config_dict: dict[str, Any] = {
"reasoning": {
"enabled": settings.DERIVER.ENABLED,
"custom_instructions": None,
},
"peer_card": {
"use": settings.PEER_CARD.ENABLED,
"create": settings.PEER_CARD.ENABLED,
},
"summary": {
"enabled": settings.SUMMARY.ENABLED,
"messages_per_short_summary": settings.SUMMARY.MESSAGES_PER_SHORT_SUMMARY,
"messages_per_long_summary": settings.SUMMARY.MESSAGES_PER_LONG_SUMMARY,
"custom_instructions": None,
},
"dream": {"enabled": settings.DREAM.ENABLED},
}
# Apply overrides in order (Workspace -> Session -> Message)
# Note: deep_update modifies config_dict in place
if workspace is not None:
deep_update(config_dict, normalize_configuration_dict(workspace.configuration))
if session is not None:
deep_update(config_dict, normalize_configuration_dict(session.configuration))
if message_configuration is not None:
deep_update(
config_dict,
normalize_configuration_dict(
message_configuration.model_dump(exclude_unset=True)
),
)
return ResolvedConfiguration(**config_dict)