Migrate saved Venice model config
Repair saved _model_config user config and presets so Venice model slots use chat completions with the Venice system prompt disabled. Leave a0_venice slots untouched and add regression coverage for parsing and slot preservation.
Alessandro committed
Jul 9, 2026 at 17:19 UTC
1bd741ff7f3fef0cc5e0a0bd91b470588d9d44da
2 files changed
+159
-2
plugins/_model_config/extensions/python/startup_migration/_10_migrate_model_config.py
+76
-2
@@ -1,7 +1,9 @@
1
import json
2
import os
3
+from copy import deepcopy
4
+
5
from helpers.extension import Extension
4
-from helpers import settings as settings_helper, files, plugins
6
+from helpers import files, plugins, yaml as yaml_helper
7
from helpers.print_style import PrintStyle
8
9
@@ -27,10 +29,20 @@ class MigrateModelConfig(Extension):
29
"browser_model_vision", "browser_model_rl_requests", "browser_model_rl_input",
30
"browser_model_rl_output", "browser_model_kwargs", "browser_http_headers",
31
]
32
+ CONFIG_SECTIONS = ("chat_model", "utility_model", "embedding_model")
33
+ PRESET_SECTIONS = ("chat", "utility", "embedding")
34
+ VENICE_KWARGS = {
35
+ "a0_api_mode": "chat",
36
+ "venice_parameters": {"include_venice_system_prompt": False},
37
+ }
38
39
def execute(self, **kwargs):
40
+ self._repair_saved_venice_config()
41
+
42
# Check if global plugin config already exists
33
- global_config_path = files.get_abs_path("plugins/_model_config/config.json")
43
+ global_config_path = files.get_abs_path(
44
+ files.USER_DIR, files.PLUGINS_DIR, "_model_config", plugins.CONFIG_FILE_NAME
45
+ )
46
if os.path.exists(global_config_path):
47
return # already migrated or manually configured
48
@@ -91,8 +103,70 @@ class MigrateModelConfig(Extension):
103
if isinstance(kw, str):
104
plugin_config[section]["kwargs"] = {}
105
106
+ self._repair_venice_config_slots(plugin_config)
107
+
108
# Save as global plugin config
109
plugins.save_plugin_config("_model_config", "", "", plugin_config)
110
PrintStyle(background_color="#6734C3", font_color="white", padding=True).print(
111
"Migrated legacy model settings to _model_config plugin config."
112
)
113
+
114
+ def _repair_saved_venice_config(self):
115
+ changed = False
116
+ config_path = files.get_abs_path(
117
+ files.USER_DIR, files.PLUGINS_DIR, "_model_config", plugins.CONFIG_FILE_NAME
118
+ )
119
+ presets_path = files.get_abs_path(
120
+ files.USER_DIR, files.PLUGINS_DIR, "_model_config", "presets.yaml"
121
+ )
122
+
123
+ if os.path.exists(config_path):
124
+ try:
125
+ config = json.loads(files.read_file(config_path))
126
+ except Exception:
127
+ config = None
128
+ if isinstance(config, dict) and self._repair_venice_config_slots(config):
129
+ files.write_file(config_path, json.dumps(config))
130
+ changed = True
131
+
132
+ if os.path.exists(presets_path):
133
+ try:
134
+ presets = yaml_helper.loads(files.read_file(presets_path))
135
+ except Exception:
136
+ presets = None
137
+ if isinstance(presets, list) and self._repair_venice_presets(presets):
138
+ files.write_file(presets_path, yaml_helper.dumps(presets))
139
+ changed = True
140
+
141
+ if changed:
142
+ PrintStyle(background_color="#6734C3", font_color="white", padding=True).print(
143
+ "Updated saved Venice model settings for chat completions."
144
+ )
145
+
146
+ def _repair_venice_config_slots(self, config: dict) -> bool:
147
+ changed = False
148
+ for section in self.CONFIG_SECTIONS:
149
+ changed = self._repair_venice_slot(config.get(section)) or changed
150
+ return changed
151
+
152
+ def _repair_venice_presets(self, presets: list) -> bool:
153
+ changed = False
154
+ for preset in presets:
155
+ if not isinstance(preset, dict):
156
+ continue
157
+ for section in self.PRESET_SECTIONS:
158
+ changed = self._repair_venice_slot(preset.get(section)) or changed
159
+ if not any(section in preset for section in self.PRESET_SECTIONS):
160
+ changed = self._repair_venice_slot(preset) or changed
161
+ return changed
162
+
163
+ def _repair_venice_slot(self, slot) -> bool:
164
+ if not isinstance(slot, dict):
165
+ return False
166
+ provider = str(slot.get("provider") or "").strip().lower()
167
+ if provider != "venice":
168
+ return False
169
+ if slot.get("kwargs") == self.VENICE_KWARGS:
170
+ return False
171
+ slot["kwargs"] = deepcopy(self.VENICE_KWARGS)
172
+ return True
tests/test_model_config_api_keys.py
+83
@@ -1,3 +1,4 @@
1
+import json
2
import sys
3
import threading
4
import types
@@ -299,6 +300,88 @@ def test_direct_venice_chat_provider_defaults_to_chat_completions(monkeypatch):
300
assert custom.kwargs["a0_api_mode"] == "responses"
301
302
303
+def test_model_config_migration_repairs_saved_venice_user_slots(monkeypatch, tmp_path):
304
+ import yaml
305
+
306
+ from helpers import files
307
+ from plugins._model_config.extensions.python.startup_migration._10_migrate_model_config import (
308
+ MigrateModelConfig,
309
+ )
310
+
311
+ monkeypatch.setattr(files, "_base_dir", str(tmp_path))
312
+ plugin_dir = tmp_path / "usr" / "plugins" / "_model_config"
313
+ plugin_dir.mkdir(parents=True)
314
+ expected = {
315
+ "a0_api_mode": "chat",
316
+ "venice_parameters": {"include_venice_system_prompt": False},
317
+ }
318
+
319
+ config_path = plugin_dir / "config.json"
320
+ config_path.write_text(
321
+ json.dumps(
322
+ {
323
+ "chat_model": {
324
+ "provider": "venice",
325
+ "name": "llama-3.3-70b",
326
+ "kwargs": {"a0_api_mode": "responses"},
327
+ },
328
+ "utility_model": {
329
+ "provider": "a0_venice",
330
+ "name": "venice-proxy",
331
+ "kwargs": {"a0_api_mode": "responses"},
332
+ },
333
+ "embedding_model": {
334
+ "provider": "venice",
335
+ "name": "embed",
336
+ "kwargs": {},
337
+ },
338
+ }
339
+ ),
340
+ encoding="utf-8",
341
+ )
342
+
343
+ presets_path = plugin_dir / "presets.yaml"
344
+ presets_path.write_text(
345
+ yaml.safe_dump(
346
+ [
347
+ {
348
+ "name": "Venice",
349
+ "chat": {
350
+ "provider": "venice",
351
+ "name": "llama-3.3-70b",
352
+ "kwargs": {"venice_parameters": {"include_venice_system_prompt": True}},
353
+ },
354
+ "utility": {
355
+ "provider": "a0_venice",
356
+ "name": "proxy",
357
+ "kwargs": {"keep": True},
358
+ },
359
+ },
360
+ {
361
+ "name": "Legacy raw preset",
362
+ "provider": "venice",
363
+ "name": "raw",
364
+ "kwargs": {"a0_api_mode": "responses"},
365
+ },
366
+ ],
367
+ sort_keys=False,
368
+ ),
369
+ encoding="utf-8",
370
+ )
371
+
372
+ MigrateModelConfig(agent=None).execute()
373
+
374
+ config = json.loads(config_path.read_text(encoding="utf-8"))
375
+ presets = yaml.safe_load(presets_path.read_text(encoding="utf-8"))
376
+
377
+ assert config["chat_model"]["kwargs"] == expected
378
+ assert config["embedding_model"]["kwargs"] == expected
379
+ assert config["utility_model"]["kwargs"] == {"a0_api_mode": "responses"}
380
+ assert presets[0]["chat"]["kwargs"] == expected
381
+ assert presets[0]["utility"]["kwargs"] == {"keep": True}
382
+ assert presets[1]["kwargs"] == expected
383
+
384
+
385
def test_local_chat_providers_default_to_chat_completions():
386
import yaml
387