settings .env+json config, logging fix
frdel committed
Aug 26, 2025 at 14:44 UTC
8a6355aa63cc554301ffba5f0d8c5cb4c81589f2
3 files changed
+53
-26
python/helpers/settings.py
+48
-25
@@ -12,6 +12,7 @@ from . import files, dotenv
12
from python.helpers.print_style import PrintStyle
13
from python.helpers.providers import get_providers
14
from python.helpers.secrets import SecretsManager
15
+from python.helpers import dirty_json
16
17
18
class Settings(TypedDict):
@@ -20,7 +21,7 @@ class Settings(TypedDict):
21
chat_model_provider: str
22
chat_model_name: str
23
chat_model_api_base: str
23
- chat_model_kwargs: dict[str, str]
24
+ chat_model_kwargs: dict[str, Any]
25
chat_model_ctx_length: int
26
chat_model_ctx_history: float
27
chat_model_vision: bool
@@ -31,7 +32,7 @@ class Settings(TypedDict):
32
util_model_provider: str
33
util_model_name: str
34
util_model_api_base: str
34
- util_model_kwargs: dict[str, str]
35
+ util_model_kwargs: dict[str, Any]
36
util_model_ctx_length: int
37
util_model_ctx_input: float
38
util_model_rl_requests: int
@@ -41,7 +42,7 @@ class Settings(TypedDict):
42
embed_model_provider: str
43
embed_model_name: str
44
embed_model_api_base: str
44
- embed_model_kwargs: dict[str, str]
45
+ embed_model_kwargs: dict[str, Any]
46
embed_model_rl_requests: int
47
embed_model_rl_input: int
48
@@ -52,8 +53,8 @@ class Settings(TypedDict):
53
browser_model_rl_requests: int
54
browser_model_rl_input: int
55
browser_model_rl_output: int
55
- browser_model_kwargs: dict[str, str]
56
- browser_http_headers: dict[str, str]
56
+ browser_model_kwargs: dict[str, Any]
57
+ browser_http_headers: dict[str, Any]
58
59
agent_profile: str
60
agent_memory_subdir: str
@@ -108,7 +109,7 @@ class Settings(TypedDict):
109
secrets: str
110
111
# LiteLLM global kwargs applied to all model calls
111
- litellm_global_kwargs: dict[str, str]
112
+ litellm_global_kwargs: dict[str, Any]
113
114
class PartialSettings(Settings, total=False):
115
pass
@@ -264,7 +265,7 @@ def convert_out(settings: Settings) -> SettingsOutput:
265
{
266
"id": "chat_model_kwargs",
267
"title": "Chat model additional parameters",
267
- "description": "Any other parameters supported by <a href='https://docs.litellm.ai/docs/set_keys' target='_blank'>LiteLLM</a>. Format is KEY=VALUE on individual lines, just like .env file.",
268
+ "description": "Any other parameters supported by <a href='https://docs.litellm.ai/docs/set_keys' target='_blank'>LiteLLM</a>. Format is KEY=VALUE on individual lines, like .env file. Value can also contain JSON objects - when unquoted, it is treated as object, number etc., when quoted, it is treated as string.",
269
"type": "textarea",
270
"value": _dict_to_env(settings["chat_model_kwargs"]),
271
}
@@ -344,7 +345,7 @@ def convert_out(settings: Settings) -> SettingsOutput:
345
{
346
"id": "util_model_kwargs",
347
"title": "Utility model additional parameters",
347
- "description": "Any other parameters supported by <a href='https://docs.litellm.ai/docs/set_keys' target='_blank'>LiteLLM</a>. Format is KEY=VALUE on individual lines, just like .env file.",
348
+ "description": "Any other parameters supported by <a href='https://docs.litellm.ai/docs/set_keys' target='_blank'>LiteLLM</a>. Format is KEY=VALUE on individual lines, like .env file. Value can also contain JSON objects - when unquoted, it is treated as object, number etc., when quoted, it is treated as string.",
349
"type": "textarea",
350
"value": _dict_to_env(settings["util_model_kwargs"]),
351
}
@@ -414,7 +415,7 @@ def convert_out(settings: Settings) -> SettingsOutput:
415
{
416
"id": "embed_model_kwargs",
417
"title": "Embedding model additional parameters",
417
- "description": "Any other parameters supported by <a href='https://docs.litellm.ai/docs/set_keys' target='_blank'>LiteLLM</a>. Format is KEY=VALUE on individual lines, just like .env file.",
418
+ "description": "Any other parameters supported by <a href='https://docs.litellm.ai/docs/set_keys' target='_blank'>LiteLLM</a>. Format is KEY=VALUE on individual lines, like .env file. Value can also contain JSON objects - when unquoted, it is treated as object, number etc., when quoted, it is treated as string.",
419
"type": "textarea",
420
"value": _dict_to_env(settings["embed_model_kwargs"]),
421
}
@@ -504,7 +505,7 @@ def convert_out(settings: Settings) -> SettingsOutput:
505
{
506
"id": "browser_model_kwargs",
507
"title": "Web Browser model additional parameters",
507
- "description": "Any other parameters supported by <a href='https://docs.litellm.ai/docs/set_keys' target='_blank'>LiteLLM</a>. Format is KEY=VALUE on individual lines, just like .env file.",
508
+ "description": "Any other parameters supported by <a href='https://docs.litellm.ai/docs/set_keys' target='_blank'>LiteLLM</a>. Format is KEY=VALUE on individual lines, like .env file. Value can also contain JSON objects - when unquoted, it is treated as object, number etc., when quoted, it is treated as string.",
509
"type": "textarea",
510
"value": _dict_to_env(settings["browser_model_kwargs"]),
511
}
@@ -514,7 +515,7 @@ def convert_out(settings: Settings) -> SettingsOutput:
515
{
516
"id": "browser_http_headers",
517
"title": "HTTP Headers",
517
- "description": "HTTP headers to include with all browser requests. Format is KEY=VALUE on individual lines, just like .env file. Example: Authorization=Bearer token123",
518
+ "description": "HTTP headers to include with all browser requests. Format is KEY=VALUE on individual lines, like .env file. Value can also contain JSON objects - when unquoted, it is treated as object, number etc., when quoted, it is treated as string. Example: Authorization=Bearer token123",
519
"type": "textarea",
520
"value": _dict_to_env(settings.get("browser_http_headers", {})),
521
}
@@ -1603,26 +1604,48 @@ def _apply_settings(previous: Settings | None):
1604
1605
1606
def _env_to_dict(data: str):
1606
- env_dict = {}
1607
- line_pattern = re.compile(r"\s*([^#][^=]*)\s*=\s*(.*)")
1607
+ result = {}
1608
for line in data.splitlines():
1609
- match = line_pattern.match(line)
1610
- if match:
1611
- key, value = match.groups()
1612
- # Remove optional surrounding quotes (single or double)
1613
- value = value.strip().strip('"').strip("'")
1614
- env_dict[key.strip()] = value
1615
- return env_dict
1609
+ line = line.strip()
1610
+ if not line or line.startswith('#'):
1611
+ continue
1612
+
1613
+ if '=' not in line:
1614
+ continue
1615
+
1616
+ key, value = line.split('=', 1)
1617
+ key = key.strip()
1618
+ value = value.strip()
1619
+
1620
+ # If quoted, treat as string
1621
+ if value.startswith('"') and value.endswith('"'):
1622
+ result[key] = value[1:-1].replace('\\"', '"') # Unescape quotes
1623
+ elif value.startswith("'") and value.endswith("'"):
1624
+ result[key] = value[1:-1].replace("\\'", "'") # Unescape quotes
1625
+ else:
1626
+ # Not quoted, try JSON parse
1627
+ try:
1628
+ result[key] = json.loads(value)
1629
+ except (json.JSONDecodeError, ValueError):
1630
+ result[key] = value
1631
+
1632
+ return result
1633
1634
1635
def _dict_to_env(data_dict):
1636
lines = []
1637
for key, value in data_dict.items():
1621
- if "\n" in value:
1622
- value = f"'{value}'"
1623
- elif " " in value or value == "" or any(c in value for c in "\"'"):
1624
- value = f'"{value}"'
1625
- lines.append(f"{key}={value}")
1638
+ if isinstance(value, str):
1639
+ # Quote strings and escape internal quotes
1640
+ escaped_value = value.replace('"', '\\"')
1641
+ lines.append(f'{key}="{escaped_value}"')
1642
+ elif isinstance(value, (dict, list, bool)) or value is None:
1643
+ # Serialize as unquoted JSON
1644
+ lines.append(f'{key}={json.dumps(value, separators=(",", ":"))}')
1645
+ else:
1646
+ # Numbers and other types as unquoted strings
1647
+ lines.append(f'{key}={value}')
1648
+
1649
return "\n".join(lines)
1650
1651
requirements.txt
+1
-1
@@ -33,7 +33,7 @@ unstructured-client==0.31.0
33
webcolors==24.6.0
34
nest-asyncio==1.6.0
35
crontab==1.0.1
36
-litellm==1.75.3
36
+litellm==1.75.0
37
markdownify==1.1.0
38
pymupdf==1.25.3
39
pytesseract==0.3.13
run_ui.py
+4
@@ -16,6 +16,10 @@ from python.helpers.extract_tools import load_classes_from_folder
16
from python.helpers.api import ApiHandler
17
from python.helpers.print_style import PrintStyle
18
19
+# disable logging
20
+import logging
21
+logging.getLogger().setLevel(logging.WARNING)
22
+
23
24
# Set the new timezone to 'UTC'
25
os.environ["TZ"] = "UTC"