1. 21 Jun, 2026 11 commits
    • Stefy Lanza (nextime / spora )'s avatar
      Group provider/rotation/autoselect config forms into collapsible sub-panels · 03f3e110
      Stefy Lanza (nextime / spora ) authored
      The provider, rotation and autoselect detail forms were single huge forms.
      Split them into collapsible sub-panels so only basic settings stay visible:
      
      - Shared subPanel()/toggleSubPanel() helper + CSS in base.html, defined
        before the content block so page scripts can call it during first render.
      - Providers: basic fields visible; Authentication, Pricing & Tiers, Rate
        limits & defaults, Feature Overrides, Native Caching, Models as panels;
        each model has basic config visible + an Advanced sub-panel.
      - Rotations: basic visible; Advanced configuration panel; one panel per
        provider (model-count + usage badge); one panel per model with an
        Advanced sub-panel.
      - Autoselect: basic visible; Classification, Feature Overrides, Default
        settings panels; one panel per available model.
      - Panel open/close state and top-level item expansion persist via
        sessionStorage, so they survive navigation within a session.
      
      Bump version to 0.99.75.
      Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
      03f3e110
    • Stefy Lanza (nextime / spora )'s avatar
      Treat HTTP 402 Payment Required as non-retryable in rotation failover · bbe17ff0
      Stefy Lanza (nextime / spora ) authored
      A 402 (e.g. Kilo "usage_limit_exceeded"/out of credits) is deterministic:
      retrying the same provider only burns the failure budget and needlessly
      disables it within a single request. Add 402 to the non-retryable set so
      the rotation fails over to the next provider immediately.
      Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
      bbe17ff0
    • Stefy Lanza (nextime / spora )'s avatar
      Routes: support model IDs with slashes; add llama.cpp/Ollama compat probes · ab8f5b69
      Stefy Lanza (nextime / spora ) authored
      - /api/v1/models/{model_id} and /api/u/{username}/models/{model_id} used a
        single-segment param, so model IDs containing '/' (e.g. rotations/lisa)
        returned 404. Use {model_id:path}.
      - Add capability-probe endpoints so OpenAI/Ollama/llama.cpp-style clients stop
        getting 404/405 on connect: GET /api/version, /v1/version, /version;
        GET /api/tags (Ollama model list); GET /props, /api/props, /v1/props.
      Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
      ab8f5b69
    • Stefy Lanza (nextime / spora )'s avatar
      Streaming support: anthropic + ollama, and true incremental streaming for google · 42e06a0c
      Stefy Lanza (nextime / spora ) authored
      - anthropic: previously ignored the stream flag entirely (always non-stream).
        Add _handle_streaming_request converting Anthropic SSE events into
        OpenAI-compatible chunks (text deltas, tool_use/input_json deltas, usage).
      - ollama: previously hard-coded stream=False. Add incremental streaming over
        /api/generate yielding OpenAI chunks.
      - google: was buffering the entire response before yielding. Stream chunks
        incrementally as they arrive when no tools are requested (the common case);
        keep the buffer-and-parse path only when tools are present, since the
        text-encoded tool-call detection needs the complete response.
      Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
      42e06a0c
    • Stefy Lanza (nextime / spora )'s avatar
      Fix rotation providers never degrading: don't record success on lazy streams · afef7809
      Stefy Lanza (nextime / spora ) authored
      For streaming requests providers returned a lazy generator and immediately
      called record_success(), resetting the failure counter to 0 BEFORE the
      rotation handler primed the stream and the upstream returned 400/429. Every
      attempt did success(reset->0) then failure(->1), so the disable threshold (3)
      was never reached and a consistently-failing provider was never disabled.
      
      Guard the premature record_success() so it does not fire for streaming
      (codex, openai, runpod, coderai). The caller already records success after
      the stream is primed/consumed, so the failure counter now accumulates and a
      failing provider is correctly disabled/cooled-down. Bump to 0.99.74.
      Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
      afef7809
    • Stefy Lanza (nextime / spora )'s avatar
      Manual disable/enable provider button (persistent across reboot) + cooldown recovery · 1d726a93
      Stefy Lanza (nextime / spora ) authored
      Adds a per-provider Disable/Enable button to the rotations page for both admin
      and users, exposing a manual disable that — unlike the failure cooldown — never
      auto-expires and persists across reboots.
      
      - providers/base.py: manual_disable()/manual_enable()/is_manually_disabled();
        manual disable takes precedence in is_rate_limited(); manual_enable() also
        clears any cooldown and resets the failure budget. Source of truth is the
        database (mirrored to cache as a fast path) so state survives restarts and
        cache flushes. Also: when a failure cooldown elapses, the provider is
        reactivated with a fresh failure budget instead of a hair-trigger.
      - database.py: dedicated provider_manual_disabled table (+migration) and
        get/set/clear helpers, user-scoped so a user's toggle never affects others.
      - dashboard: manual-disable / manual-enable / bulk manual-status endpoints; the
        rotations pages render and toggle the button state.
      
      Bump to 0.99.73.
      Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
      1d726a93
    • Stefy Lanza (nextime / spora )'s avatar
      Optional rotation/autoselect override for the internal local models · df8d927d
      Stefy Lanza (nextime / spora ) authored
      Each internal-model functionality can now point at a rotation or autoselect
      instead of the local model, falling back to the local model when the override is
      empty or fails. Per-functionality fields in internal_model (default empty):
      condensation_override, autoselect_override, nsfw_classifier_override,
      privacy_classifier_override.
      
      - handlers.py: run_meta_target() runs a global rotation/autoselect and returns
        the assistant text (or None -> fallback); classification overrides prompt the
        chat model for a strict YES/NO and parse it, falling back to the local
        classifier; autoselect selection can run through an override.
      - context.py: condensation prefers the override, falling back to the local model.
      - settings page: per-field override inputs backed by a datalist of available
        rotations/autoselects; saved to internal_model.
      Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
      df8d927d
    • Stefy Lanza (nextime / spora )'s avatar
      Rotation entries can forward to a rotation/autoselect, with loop protection · c666aab2
      Stefy Lanza (nextime / spora ) authored
      A rotation provider entry whose provider_id is "rotations" or "autoselect" is a
      meta-provider: each model "name" is the id of a target rotation/autoselect, and
      the request is forwarded there (weighted like any other entry, with failover to
      the next entry on total failure).
      
      - handlers.py: detect meta-providers in model-building, delegate in the retry
        loop, and resolve rotation vs autoselect targets.
      - Loop protection: a delegation chain rides on request_data and is registered by
        both RotationHandler and AutoselectHandler; re-entering an id already in the
        chain (A->B->A) or exceeding depth 8 raises HTTP 508 (caught upstream -> fail
        over). Loops are also pre-filtered at model-build time.
      - Dashboard: the provider select in rotations.html / user_rotations.html now
        offers "rotations"/"autoselect"; the model row becomes a target picker.
      Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
      c666aab2
    • Stefy Lanza (nextime / spora )'s avatar
      Notify client on rotation failover (banner/metadata/headers); bump to 0.99.71 · 0a3a1df7
      Stefy Lanza (nextime / spora ) authored
      When a rotation fails over to a different provider/model than the preferred
      (highest-weight) pick, optionally notify the client so the provider/model
      change isn't silent. Opt-in via a new notify_on_failover flag, settable
      globally (rotations.json top-level) or per-rotation, mirroring notifyerrors.
      
      On a real switch (served provider/model differs from preferred), three
      mechanisms carry the notice:
      - Visible banner: prepended to message content (non-streaming) or a leading
        delta chunk (streaming).
      - JSON metadata: an aisbf_failover object on the body / leading stream chunk.
      - HTTP headers: X-AISBF-Failover/Provider/Model/Preferred-* on the
        StreamingResponse and (for non-streaming) at the rotation route.
      
      Applied to both the normal and chunked rotation paths. The banner is injected
      after caching so cache hits don't replay a stale notice; no switch means zero
      overhead and nothing emitted; default off preserves existing behavior.
      Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
      0a3a1df7
    • Stefy Lanza (nextime / spora )'s avatar
      Transparent rotation failover for streaming provider errors; bump to 0.99.70 · d9227cb1
      Stefy Lanza (nextime / spora ) authored
      Streaming rotation requests returned the provider's lazy async generator to
      the client before the upstream HTTP call was made, so an immediate provider
      error (e.g. HTTP 400 "model not supported") surfaced mid-stream after the
      200 OK headers were already sent — leaking the error to the client instead
      of failing over.
      
      - Prime streaming responses (_prime_stream) inside the rotation retry loop so
        immediate provider errors are raised within the try/except and trigger
        failover to the next provider by weight, transparently to the client.
      - Add _is_non_retryable_error to skip pointless same-provider retries for
        client errors (400/401/403/404/405/422) and move straight to the next
        provider; 5xx/timeouts/network remain retryable.
      Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
      d9227cb1
    • Stefy Lanza (nextime / spora )'s avatar
      Fix missing market/usage helpers on Rotation & Autoselect handlers; bump to 0.99.69 · bd7bfb97
      Stefy Lanza (nextime / spora ) authored
      Add _record_dashboard_proxy_event, _settle_market_result,
      _get_market_source_details, _market_request_id and
      _extract_usage_from_sse_chunk to RotationHandler, and the market
      settlement cluster to AutoselectHandler. These were defined only on
      RequestHandler, so rotation/autoselect requests raised AttributeError
      (crash on the dashboard event path, silently swallowed elsewhere),
      dropping market settlement and streaming usage capture.
      Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
      bd7bfb97
  2. 19 Jun, 2026 1 commit
  3. 19 May, 2026 2 commits
  4. 18 May, 2026 6 commits
  5. 17 May, 2026 4 commits
  6. 16 May, 2026 3 commits
  7. 14 May, 2026 1 commit
  8. 13 May, 2026 4 commits
  9. 12 May, 2026 8 commits