{% extends "org-base.html" %} {% from "ui.html" import csrf_field, action, when, copyable with context %} {% from "provider-help.html" import key_help with context %} {% set keyless = ('ollama', 'openai_compatible', 'claude_code', 'codex') %} {% set effort_labels = {"low": _("Low"), "medium": _("Medium"), "high": _("High"), "max": _("Maximum")} %} {% block section %}

{{ _("Used by the nightly tidy-up in all the organization's spaces; each space may pick another model.") }}

{% if ai %}
{{ _(provider_labels.get(ai.provider, ai.provider)) }}{% if ai.model %} · {{ ai.model }}{% endif %} {% if not ai.has_key and ai.provider not in keyless %}

{{ _("No key: the tidy-up cannot run") }}

{% elif ai.test_pending %}

{{ _("Test in progress…") }} {{ _("in the worker, the only container with access to the CLI; this page updates itself.") }} {{ _("Refresh") }}

{% elif ai.test_ok is none %}

{{ _("Not tested yet") }}

{% elif ai.test_ok %}

{{ _("Reachable") }} {{ _("tested") }} {{ when(ai.tested_at) }}

{% else %}

{{ _("Unreachable") }} {{ when(ai.tested_at) }}

{{ _(ai.test_message) }}

{% endif %} {% if spending %}

{{ _("This month: {spent}", spent=spending.spent|euros) }}{% if spending.budget %} {{ _("of {budget}", budget=spending.budget|euros) }}{% endif %}{% if spending.subscription %} · {{ _("subscription: no per-use cost") }}{% endif %}

{% endif %}
{{ action("/o/" ~ org.slug ~ "/-/ai/test", _("Test the connection")) }}
{% if ai.metered and ai.monthly_budget is none %} {% endif %} {% else %}
{{ _("No provider configured: the nightly tidy-up cannot run.") }}
{% endif %}
{{ csrf_field() }}

{{ _("Encrypted, never shown again.", context="key") }}

{{ key_help(('anthropic', 'openai', 'mistral', 'ollama', 'openai_compatible')) }} {% if ai and ai.has_key %}{% endif %} {# Subscription: neither per-token pricing nor a budget in euros, the plan is paid separately. #}
{{ _("Cost and budget") }}

{% if public_price %}{{ _("Empty: the model's public price, ${input} / ${output} per million tokens, counted $1 = €1 (the cost shown is an estimate).", input=public_price[0], output=public_price[1]) }}{% else %}{{ _("Empty: no cost is computed for this model. Subscriptions have no per-use cost.") }}{% endif %}

{# Budget suggested on first setup (or when leaving a subscription); no effect for Ollama or a compatible API without a key (see org_ai_update). #} {% set suggest = (not ai or ai.provider in ('claude_code', 'codex')) %}
{% if suggest %}{% endif %}

{{ _("Administrators are notified at 80%; at 100%, the tidy-up is paused until the following month.") }}{% if suggest %} {{ _("Suggested amount for a pay-per-use API key; ignored for Ollama.") }}{% endif %}

{% if user.is_superadmin or (ai and ai.provider in ('claude_code', 'codex')) %} {% if user.is_superadmin and legacy_logins %} {# The worker connection already works: only the old copy remains to be deleted. #} {% set worker_ok = ai and ai.provider in ('claude_code', 'codex') and ai.test_ok and not ai.test_pending %} {% endif %} {% for provider in ('claude_code', 'codex') %}

{% if provider == 'claude_code' %}{{ _("Connect Claude Code on the server") }}{% else %}{{ _("Connect Codex on the server") }}{% endif %}

{{ _("Once, by the server administrator. Synaptane never sees the credentials: they stay in the official CLI. Empty model: the CLI's default.") }}

  1. {% if docker %}{{ _("On the server, in the Synaptane folder (the one with compose.yaml), run:") }}{% else %}{{ _("On the server, as the system user running “synaptane worker”, run:") }}{% endif %} {{ copyable("login-" ~ provider, cli_login[provider], block=true) }}
  2. {% if provider == 'claude_code' %}
  3. {{ _("Open the address shown in your browser, sign in with your Claude account (Pro or Max) and authorize access.") }}
  4. {{ _("Copy the code shown by Claude, paste it into the terminal and press Enter.") }}
  5. {% else %}
  6. {{ _("Open the address shown in your browser, sign in with your ChatGPT account (Plus or Pro) and enter the code shown in the terminal.") }}
  7. {% endif %}
  8. {{ _("Save this provider above, then click “Test the connection”.") }}
{% if docker %}

{{ _("The login is kept in a volume of its own, mounted only in the worker, not in the web container: it survives updates and image rebuilds, but “docker compose down -v” erases it. The connection test therefore runs in the worker.") }}

{% endif %}
{% endfor %} {% endif %}
{% endblock %}