mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-20 21:48:47 +02:00
save full agent config per model
This commit is contained in:
1 parent
f6793daed3
commit
c794d58718
3 files changed
+65
-27
No files matched your search
+32
-25
@@ -10,13 +10,14 @@ from . import db
|
|||||||
CONFIG_KEY = "agent"
|
CONFIG_KEY = "agent"
|
||||||
MODEL_PROFILES_KEY = "model_profiles"
|
MODEL_PROFILES_KEY = "model_profiles"
|
||||||
PROFILE_STATE_KEY = "model_profiles_state"
|
PROFILE_STATE_KEY = "model_profiles_state"
|
||||||
PROFILE_VERSION = 4
|
PROFILE_VERSION = 5
|
||||||
|
|
||||||
DEFAULT_SYSTEM_PROMPT = (
|
DEFAULT_SYSTEM_PROMPT = (
|
||||||
"Tu es Loki, un assistant de développement local agentique. Tu disposes "
|
"Tu es Loki, un assistant de développement local agentique. Tu disposes "
|
||||||
"d'outils pour lire, écrire et lister des fichiers dans le workspace. "
|
"d'outils pour lire, écrire et lister des fichiers dans le workspace. "
|
||||||
"Utilise-les pour accomplir les tâches concrètement, puis réponds de façon "
|
"Utilise-les pour accomplir les tâches concrètement, puis réponds de façon "
|
||||||
"concise en français. Pour un fichier long, appelle write_file en plusieurs "
|
"concise en français. Quand tu appelles write_file, fournis toujours "
|
||||||
|
"`path` et `content`. Pour un fichier long, appelle write_file en plusieurs "
|
||||||
"morceaux (overwrite puis append) afin de toujours produire un JSON valide. "
|
"morceaux (overwrite puis append) afin de toujours produire un JSON valide. "
|
||||||
"Après avoir écrit un fichier, propose un aperçu. "
|
"Après avoir écrit un fichier, propose un aperçu. "
|
||||||
"Formate TOUJOURS tes réponses en Markdown : titres, listes, gras pour les "
|
"Formate TOUJOURS tes réponses en Markdown : titres, listes, gras pour les "
|
||||||
@@ -45,6 +46,13 @@ GENERATION_FIELDS = {
|
|||||||
"num_gpu",
|
"num_gpu",
|
||||||
"num_batch",
|
"num_batch",
|
||||||
}
|
}
|
||||||
|
PROFILE_FIELDS = {
|
||||||
|
"system_prompt",
|
||||||
|
"tools",
|
||||||
|
"confirm_shell",
|
||||||
|
"think",
|
||||||
|
*GENERATION_FIELDS,
|
||||||
|
}
|
||||||
|
|
||||||
DEFAULT_GENERATION: dict = {
|
DEFAULT_GENERATION: dict = {
|
||||||
"temperature": 0.7,
|
"temperature": 0.7,
|
||||||
@@ -106,42 +114,41 @@ def _migrate_profiles() -> None:
|
|||||||
db.set_config_value(PROFILE_STATE_KEY, {"version": PROFILE_VERSION})
|
db.set_config_value(PROFILE_STATE_KEY, {"version": PROFILE_VERSION})
|
||||||
|
|
||||||
|
|
||||||
def get_config(model: str | None = None) -> dict:
|
def _clean_tools(value: dict | None, fallback: dict | None = None) -> dict:
|
||||||
"""Configuration globale complétée par le profil du modèle demandé."""
|
fallback = fallback or DEFAULT_TOOL_STATE
|
||||||
_migrate_profiles()
|
return {
|
||||||
stored = db.get_config_value(CONFIG_KEY) or {}
|
name: bool((value or {}).get(name, fallback.get(name, DEFAULT_TOOL_STATE[name])))
|
||||||
global_stored = {k: v for k, v in stored.items() if k not in GENERATION_FIELDS}
|
|
||||||
cfg = {**DEFAULT_CONFIG, **global_stored}
|
|
||||||
if model:
|
|
||||||
profiles = db.get_config_value(MODEL_PROFILES_KEY) or {}
|
|
||||||
cfg.update({**_default_generation(model), **profiles.get(model, {})})
|
|
||||||
cfg["tools"] = {
|
|
||||||
name: bool(stored.get("tools", {}).get(name, DEFAULT_TOOL_STATE[name]))
|
|
||||||
for name in AVAILABLE_TOOLS
|
for name in AVAILABLE_TOOLS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_config(model: str | None = None) -> dict:
|
||||||
|
"""Configuration complète, avec surcharge sauvegardée par modèle."""
|
||||||
|
_migrate_profiles()
|
||||||
|
stored = db.get_config_value(CONFIG_KEY) or {}
|
||||||
|
cfg = {**DEFAULT_CONFIG, **stored}
|
||||||
|
cfg["tools"] = _clean_tools(stored.get("tools"))
|
||||||
|
if model:
|
||||||
|
profiles = db.get_config_value(MODEL_PROFILES_KEY) or {}
|
||||||
|
profile = profiles.get(model, {})
|
||||||
|
cfg.update({**_default_generation(model), **profile})
|
||||||
|
cfg["tools"] = _clean_tools(profile.get("tools"), cfg["tools"])
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
def save_config(patch: dict, model: str | None = None) -> dict:
|
def save_config(patch: dict, model: str | None = None) -> dict:
|
||||||
"""Sauvegarde le comportement global et la génération par modèle."""
|
"""Sauvegarde tous les réglages, globalement ou pour un modèle."""
|
||||||
clean = {k: v for k, v in patch.items() if v is not None}
|
clean = {k: v for k, v in patch.items() if v is not None}
|
||||||
cfg = {**get_config(model), **clean}
|
cfg = {**get_config(model), **clean}
|
||||||
if "tools" in patch and patch["tools"]:
|
if "tools" in patch and patch["tools"]:
|
||||||
cfg["tools"] = {
|
cfg["tools"] = _clean_tools(patch["tools"], cfg["tools"])
|
||||||
name: bool(
|
|
||||||
patch["tools"].get(
|
|
||||||
name, cfg["tools"].get(name, DEFAULT_TOOL_STATE[name])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
for name in AVAILABLE_TOOLS
|
|
||||||
}
|
|
||||||
global_cfg = {k: v for k, v in cfg.items() if k not in GENERATION_FIELDS}
|
|
||||||
db.set_config_value(CONFIG_KEY, global_cfg)
|
|
||||||
|
|
||||||
if model:
|
if model:
|
||||||
profiles = db.get_config_value(MODEL_PROFILES_KEY) or {}
|
profiles = db.get_config_value(MODEL_PROFILES_KEY) or {}
|
||||||
profiles[model] = {field: cfg[field] for field in GENERATION_FIELDS}
|
profiles[model] = {field: cfg[field] for field in PROFILE_FIELDS}
|
||||||
db.set_config_value(MODEL_PROFILES_KEY, profiles)
|
db.set_config_value(MODEL_PROFILES_KEY, profiles)
|
||||||
|
else:
|
||||||
|
db.set_config_value(CONFIG_KEY, {field: cfg[field] for field in PROFILE_FIELDS})
|
||||||
return get_config(model)
|
return get_config(model)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+31
-1
@@ -275,13 +275,43 @@ TOOL_DEFINITIONS = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _normalize_args(name: str, args: dict | None) -> dict:
|
||||||
|
args = dict(args or {})
|
||||||
|
if name == "write_file":
|
||||||
|
if "path" not in args:
|
||||||
|
for alias in ("file_path", "filepath", "filename", "file", "name"):
|
||||||
|
if args.get(alias):
|
||||||
|
args["path"] = args[alias]
|
||||||
|
break
|
||||||
|
if "content" not in args:
|
||||||
|
for alias in ("text", "body", "data", "contents"):
|
||||||
|
if alias in args:
|
||||||
|
args["content"] = args[alias]
|
||||||
|
break
|
||||||
|
elif name in {"read_file", "list_dir"} and "path" not in args:
|
||||||
|
for alias in ("file_path", "filepath", "filename", "file", "dir", "directory"):
|
||||||
|
if args.get(alias):
|
||||||
|
args["path"] = args[alias]
|
||||||
|
break
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
def run_tool(name: str, args: dict) -> dict:
|
def run_tool(name: str, args: dict) -> dict:
|
||||||
"""Exécute un outil par son nom ; lève ToolError si inconnu/invalide."""
|
"""Exécute un outil par son nom ; lève ToolError si inconnu/invalide."""
|
||||||
impl = TOOL_IMPL.get(name)
|
impl = TOOL_IMPL.get(name)
|
||||||
if impl is None:
|
if impl is None:
|
||||||
raise ToolError(f"outil inconnu : {name}")
|
raise ToolError(f"outil inconnu : {name}")
|
||||||
|
args = _normalize_args(name, args)
|
||||||
|
if name == "write_file":
|
||||||
|
missing = [key for key in ("path", "content") if key not in args]
|
||||||
|
if missing:
|
||||||
|
raise ToolError(
|
||||||
|
"arguments invalides pour write_file : "
|
||||||
|
f"{', '.join(missing)} requis. Utilise par exemple "
|
||||||
|
'{"path":"index.html","content":"...","mode":"overwrite"}.'
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
return impl(**(args or {}))
|
return impl(**args)
|
||||||
except ToolError:
|
except ToolError:
|
||||||
raise
|
raise
|
||||||
except TypeError as exc:
|
except TypeError as exc:
|
||||||
|
|||||||
@@ -100,7 +100,8 @@ export function SettingsView() {
|
|||||||
MODÈLE & GÉNÉRATION
|
MODÈLE & GÉNÉRATION
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 text-[14px] text-muted-2">
|
<div className="mt-2 text-[14px] text-muted-2">
|
||||||
Choisis le modèle local et règle son comportement.
|
Choisis le modèle local et règle son comportement. Les changements
|
||||||
|
sont sauvegardés pour le modèle sélectionné.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
|
|||||||
Reference in new issue
Block a user