mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-11-01 10:42:23 +01:00
* fix(editor): stabilize image workflows and editing controls
* docs(editor): add desktop and mobile visual validation evidence
* fix(editor): synchronize quick edit model events and register imagePreferences in test coordinator
* fix(settings): enforce authoritative global image-gen policy and non-admin preference persistence
- Enforce authoritative administrator global image_gen_enabled disable in get_user_setting, do_generate_image, and image_editing_provider_available, preventing non-admin user preference overrides while preserving user-disabled opt-outs and can_generate_images privilege checks across direct, gallery, and editor paths.
- Filter non-admin preference persistence in saveImagePreferences to user preference keys only (image_model, image_edit_model, image_quality), preventing global policy toggles from leaking into user preferences.
- Return accurate 200 OK Response from saveImagePreferences after fallback persistence succeeds so settings UI displays 'Saved' instead of false 403 error, while retaining visibility of real errors.
- Load per-user preferences via readImagePreferences in initImageSettings so non-admin selections persist and display correctly after page reload.
- Clear per-user model preferences on successful admin save (POST /api/auth/settings) via PUT /api/prefs/{key} with value: null to prevent stale per-user preferences from shadowing updated global settings.
- Support clearing keys in PUT /api/prefs/{key} when value is null.
- Add comprehensive Python regression tests for global-disabled/user-enabled, global-enabled/user-disabled, and authorized generation, plus Node and browser regression tests for non-admin persistence, toggle isolation, reload, and admin clearing.
* fix(settings): invalidate shared appConfig cache near auth settings write
* fix(test): isolate test_tool_policy unit suite from external model endpoint state
* fix(test): isolate web_fetch failure regression from contextual follow-up heuristics
* fix(test): isolate test_tool_policy from cross-test approval gate state
Ensure _patch_loop_basics disables TOOL_APPROVAL_GATE_ENABLED so routing tests in test_tool_policy run in the intended opt-out posture even when prior tests populate DATA_DIR with skills or untrusted context. Remove unnecessary forced_tools and contextual web mock workarounds.
* fix(settings): isolate non-admin image toggle and surface preference cleanup errors
- Restrict image generation availability toggle to admin users in imageModels.js, disabling the switch for non-admins and reverting unauthorized changes with an explicit message.
- Separate non-admin image model preference saves from global toggle updates.
- Track preference cleanup results on admin save in imagePreferences.js, propagating cleanup failures instead of ignoring them.
- Require valid preference keys on 403 fallback so toggle-only attempts reject cleanly.
- Add /api/prefs route mock to test_image_model_settings_sync_both_directions_and_survive_reopening.
- Add regression coverage for admin cleanup failures and non-admin toggle rejection.
* fix(settings): reconcile admin toggle on partial cleanup failure and report errors
- In imagePreferences.js, distinguish pre-persistence failures from post-save cleanup failures using err.globalSaved and err.phase.
- In imagePreferences.js, notify listeners of global policy updates on partial success before propagating cleanup failure.
- In imageModels.js, retain the persisted target state on admin toggle when global persistence succeeds but cleanup fails.
- In imageModels.js, reconcile admin toggle with authoritative server state via readImagePreferences() after ambiguous or partial failures.
- In imageModels.js, report partial success accurately without suppressing preference cleanup error messages.
- Add regression coverage in test_settings_save_response_ok_js.py for cleanup HTTP 500, cleanup network rejection, successful cleanup, and failed global POST.
---------
Co-authored-by: pewdiepie-archdaemon <pewdiepie-archdaemon@users.noreply.github.com>
Co-authored-by: Alexandre Teixeira <general@alexandreteixeira.dev>
70 lines
2.4 KiB
Python
70 lines
2.4 KiB
Python
"""Small helpers for recognizing image-generation model IDs."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import math
|
|
|
|
|
|
_IMAGE_MODEL_PREFIXES = (
|
|
"gpt-image",
|
|
"dall-e",
|
|
"chatgpt-image",
|
|
"hidream",
|
|
"qwen-image",
|
|
"z-image",
|
|
"flux",
|
|
"stable-diffusion",
|
|
"sdxl",
|
|
"boogu",
|
|
"krea-2",
|
|
)
|
|
|
|
|
|
def model_id_leaf(model_id: str) -> str:
|
|
"""Return the provider-stripped model id leaf in lowercase."""
|
|
return str(model_id or "").strip().split("/")[-1].lower()
|
|
|
|
|
|
def image_edit_size(model_id: str, width: int, height: int) -> str:
|
|
"""Match source geometry within the fixed GPT Image 1 output sizes."""
|
|
if width <= 0 or height <= 0:
|
|
raise ValueError("Image dimensions must be positive")
|
|
leaf = model_id_leaf(model_id)
|
|
if leaf in {"gpt-image-1", "gpt-image-1-mini", "gpt-image-1.5",
|
|
"gpt-5-image", "gpt-5-image-mini"}:
|
|
sizes = ((1024, 1024), (1536, 1024), (1024, 1536))
|
|
width, height = min(sizes, key=lambda candidate: (
|
|
abs(math.log((candidate[0] / candidate[1]) / (width / height))),
|
|
abs(candidate[0] * candidate[1] - width * height),
|
|
))
|
|
return f"{width}x{height}"
|
|
|
|
|
|
def image_aspect_ratio(width: int, height: int) -> str:
|
|
"""Choose the nearest common Image API ratio, without distorting pixels."""
|
|
if width <= 0 or height <= 0:
|
|
raise ValueError("Image dimensions must be positive")
|
|
ratios = ((1, 1), (16, 9), (9, 16), (3, 2), (2, 3), (4, 3), (3, 4), (21, 9))
|
|
w, h = min(ratios, key=lambda ratio: abs(math.log((ratio[0] / ratio[1]) / (width / height))))
|
|
return f"{w}:{h}"
|
|
|
|
|
|
def looks_like_image_generation_model(model_id: str) -> bool:
|
|
"""Return True when a model id should use image generation routes.
|
|
|
|
API providers can namespace image models, e.g. ``openai/gpt-5-image``.
|
|
Classify by the leaf so mixed endpoints can expose chat and image models
|
|
without marking the whole endpoint as image-only.
|
|
"""
|
|
mid = str(model_id or "").strip().lower()
|
|
leaf = model_id_leaf(mid)
|
|
if not leaf:
|
|
return False
|
|
if any(leaf.startswith(prefix) for prefix in _IMAGE_MODEL_PREFIXES):
|
|
return True
|
|
# Newer OpenAI image models use names like gpt-5-image instead of
|
|
# gpt-image-1. Keep this pattern provider-agnostic.
|
|
return (leaf.startswith("gpt-") and "-image" in leaf) or (
|
|
leaf.startswith("gemini-") and "image" in leaf
|
|
)
|