OXYGENHUB
# d1727c573f30 oxygenhub / templates / assistants_panel.html
5.9 KiB · HTML · last changed AI assistants: settings per site, organisation and repository 1 month ago source blame history raw
1
{% macro panel(base, a, csrf, what) %}
2
<section class="panel" id="assistants">
3
  <h2>AI assistants</h2>
4
  <p class="small mute">{{ what }} An assistant reviews a proposal when asked, or drafts its description; its answers are shown as the person who asked, via the assistant. It never approves.</p>
5
  {% if !a.inherited.is_empty() %}
6
  <h3>Inherited</h3>
7
  <ul class="hooks">
8
  {% for i in a.inherited %}
9
  <li class="hook">
10
    <div class="hook-head"><strong>{{ i.assistant.name }}</strong> <span class="tag">{{ i.assistant.model }}</span>
11
      {% if i.on() %}<span class="tag head">on</span>{% else if i.off_above %}<span class="tag dim">off above</span>{% else %}<span class="tag dim">off</span>{% endif %}
12
      <span class="small mute">from {{ i.from }}</span></div>
13
  </li>
14
  {% endfor %}
15
  </ul>
16
  {% endif %}
17
  {% if a.own.is_empty() %}<p class="mute small">{% if a.inherited.is_empty() %}None.{% else %}None of its own.{% endif %}</p>{% else %}
18
  <ul class="hooks">
19
  {% for o in a.own %}{% let r = o.assistant %}
20
  <li class="hook">
21
    <div class="hook-head">
22
      <strong>{{ r.name }}</strong> <span class="tag">{{ r.model }}</span> <span class="tag">{{ r.api }}</span>
23
      {% if o.on() %}<span class="tag head">on</span>{% else if o.off_above %}<span class="tag dim" title="An assistant of this name is turned off at a level above">off above</span>{% else %}<span class="tag dim">off</span>{% endif %}
24
    </div>
25
    <p class="small mute"><code>{{ r.endpoint }}</code> · token {% if r.has_token() %}set{% else %}none{% endif %} · context {{ r.budget }} characters</p>
26
    <form class="tiny" method="post" action="{{ base }}/assistants"><input type="hidden" name="_csrf" value="{{ csrf }}"><input type="hidden" name="id" value="{{ r.id }}"><button name="action" value="toggle">{% if r.enabled %}turn off{% else %}turn on{% endif %}</button> <button name="action" value="test">test</button> <button name="action" value="delete" class="danger-btn" onclick="return confirm('Delete {{ r.name }}?')">delete</button></form>
27
    <details class="hook-edit"><summary class="small">edit</summary>
28
      <form class="card" method="post" action="{{ base }}/assistants">
29
        <input type="hidden" name="_csrf" value="{{ csrf }}"><input type="hidden" name="id" value="{{ r.id }}"><input type="hidden" name="action" value="update">
30
        <label for="an{{ r.id }}">Name</label><input type="text" id="an{{ r.id }}" name="name" value="{{ r.name }}">
31
        <label for="ae{{ r.id }}">Endpoint</label><input type="text" id="ae{{ r.id }}" name="endpoint" value="{{ r.endpoint }}" autocomplete="off">
32
        <label for="aa{{ r.id }}">API</label>
33
        <select id="aa{{ r.id }}" name="api">{% for api in a.apis %}<option value="{{ api }}"{% if r.api == *api %} selected{% endif %}>{{ api }}</option>{% endfor %}</select>
34
        <label for="am{{ r.id }}">Model</label><input type="text" id="am{{ r.id }}" name="model" value="{{ r.model }}">
35
        <label for="at{{ r.id }}">Token</label><input type="password" id="at{{ r.id }}" name="token" placeholder="{% if r.has_token() %}unchanged{% else %}none{% endif %}" autocomplete="new-password">
36
        <label for="ah{{ r.id }}">Extra headers</label><textarea id="ah{{ r.id }}" name="headers" rows="2" placeholder="Name: value">{{ r.headers }}</textarea>
37
        <label for="ab{{ r.id }}">Context budget (characters)</label><input type="text" id="ab{{ r.id }}" name="budget" value="{{ r.budget }}">
38
        <div class="choice"><label><input type="checkbox" name="enabled" value="1"{% if r.enabled %} checked{% endif %}> on</label></div>
39
        <button type="submit">SAVE</button>
40
      </form>
41
    </details>
42
  </li>
43
  {% endfor %}
44
  </ul>{% endif %}
45
  <form class="card" method="post" action="{{ base }}/assistants">
46
    <input type="hidden" name="_csrf" value="{{ csrf }}"><input type="hidden" name="action" value="add">
47
    <h3>Add an assistant</h3>
48
    <label for="aname">Name</label><input type="text" id="aname" name="name" placeholder="Claude" required>
49
    <label for="aendpoint">Endpoint</label><input type="text" id="aendpoint" name="endpoint" placeholder="https://api.anthropic.com/v1/messages" required autocomplete="off">
50
    <label for="aapi">API</label>
51
    <select id="aapi" name="api">{% for api in a.apis %}<option value="{{ api }}">{{ api }}{% if *api == "chat-completions" %} (OpenAI, DeepSeek, Ollama, most others){% else %} (Anthropic){% endif %}</option>{% endfor %}</select>
52
    <label for="amodel">Model</label><input type="text" id="amodel" name="model" placeholder="claude-opus-5-5" required>
53
    <label for="atoken">Token</label><input type="password" id="atoken" name="token" autocomplete="new-password">
54
    <p class="small mute">Sent as a bearer token, or as the API key for Anthropic; kept sealed on the server and never shown again. Leave it empty for an endpoint that needs none.</p>
55
    <label for="aheaders">Extra headers</label><textarea id="aheaders" name="headers" rows="2" placeholder="Name: value"></textarea>
56
    <label for="abudget">Context budget (characters)</label><input type="text" id="abudget" name="budget" value="{{ a.default_budget }}">
57
    <div class="choice"><label><input type="checkbox" name="enabled" value="1" checked> on</label></div>
58
    <button type="submit">ADD</button>
59
  </form>
60
  <form class="card" method="post" action="{{ base }}/assistants">
61
    <input type="hidden" name="_csrf" value="{{ csrf }}"><input type="hidden" name="action" value="prompt">
62
    <h3>Prompt</h3>
63
    {% for (from, text) in a.inherited_prompts %}<details><summary class="small mute">From {{ from }}</summary><pre class="snippet">{{ text }}</pre></details>{% endfor %}
64
    <label for="aprompt">What every assistant is told here{% if !a.inherited_prompts.is_empty() %}, after the prompts above{% endif %}</label>
65
    <textarea id="aprompt" name="prompt" rows="6" placeholder="Review for correctness first. This project is written in Rust; the style guide is in docs/style.md.">{{ a.prompt }}</textarea>
66
    <button type="submit">SAVE PROMPT</button>
67
  </form>
68
</section>
69
{% endmacro %}