You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Give the semantic index its own Administration menu entry
The index rebuild control was buried at the bottom of the Company settings
page, where it was hard to find. Move it to a dedicated "Semantic index" page
with its own sidebar entry under Administration, next to "Assistant feedback".
- New SemanticIndexAdminView (GET, system.config.read) renders the status card
(indexed/total, last updated, embedding model) and the rebuild button.
- Sidebar link shown when AI_ASSISTANT_ENABLED and the user has
system.config.read; gated icon bi-stars.
- Rebuild POST redirects back to the new page; card removed from Company
settings (and its context reverted).
- French translations, a page render + permission test, and docs/CHANGELOG
updated to point at Administration -> Semantic index.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CHANGELOG.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
11
11
12
12
-**Ask Cairn: OpenAI and OpenAI-compatible providers**: the assistant gains an `openai` backend (`AI_ASSISTANT_PROVIDER=openai`) that targets OpenAI (ChatGPT, e.g. `gpt-4o-mini`) out of the box and, via `AI_ASSISTANT_BASE_URL`, any other endpoint implementing the OpenAI `/chat/completions` and `/embeddings` API (vLLM, LiteLLM, LocalAI, Together, Groq...). The shared request/response handling was extracted into a generic `OpenAICompatibleClient`; the existing `MistralClient` is now a thin subclass of it (Mistral already exposes an OpenAI-compatible API), so behaviour is unchanged for Mistral users. `AI_ASSISTANT_BASE_URL` now defaults to empty and each provider falls back to its own endpoint (`mistral` -> `api.mistral.ai`, `openai` -> `api.openai.com`, `anthropic` -> `api.anthropic.com`); set it only to target a custom gateway.
13
13
-**Ask Cairn: Claude (Anthropic) provider**: a native `anthropic` backend (`AI_ASSISTANT_PROVIDER=anthropic`) talks to Claude through the Messages API (`POST /v1/messages`, `x-api-key` header, top-level `system`, `content` block list) - Claude is not OpenAI-compatible, so it has its own client. Routing uses forced tool use (a `plan` tool whose `input_schema` is the routing schema) and no `temperature`/`thinking` is sent (both 400 on the current Opus family). Set `AI_ASSISTANT_MODEL` to a Claude model id (e.g. `claude-opus-4-8`). Semantic search is not available with this provider, since Anthropic has no embeddings API.
14
-
-**Ask Cairn: automatic semantic index maintenance**: the requirement semantic index now stays fresh without a manual command. A `post_delete` signal prunes a deleted requirement's embedding immediately (no provider call); the index is refreshed in a guarded background thread when a server process starts (when `AI_ASSISTANT_SEMANTIC_ENABLED`); and the Company settings page gains an index-status panel (indexed / total requirements, last updated, embedding model) with an **"Update the index now"** button (gated by `system.config.update`) that triggers a background rebuild. Embedding stays off the request path - requirement saves never embed inline; the documented daily `rebuild_semantic_index` cron remains the self-healing backstop. The rebuild logic was extracted into `assistant.semantic.rebuild_index` / `rebuild_index_async` (cache-locked to dedupe overlapping triggers) and reused by the management command.
14
+
-**Ask Cairn: automatic semantic index maintenance**: the requirement semantic index now stays fresh without a manual command. A `post_delete` signal prunes a deleted requirement's embedding immediately (no provider call); the index is refreshed in a guarded background thread when a server process starts (when `AI_ASSISTANT_SEMANTIC_ENABLED`); and a dedicated **Administration -> Semantic index**page shows an index-status panel (indexed / total requirements, last updated, embedding model) with an **"Update the index now"** button (gated by `system.config.update`) that triggers a background rebuild. Embedding stays off the request path - requirement saves never embed inline; the documented daily `rebuild_semantic_index` cron remains the self-healing backstop. The rebuild logic was extracted into `assistant.semantic.rebuild_index` / `rebuild_index_async` (cache-locked to dedupe overlapping triggers) and reused by the management command.
Copy file name to clipboardExpand all lines: accounts/templates/accounts/company_settings.html
-43Lines changed: 0 additions & 43 deletions
Original file line number
Diff line number
Diff line change
@@ -85,49 +85,6 @@ <h2>{% trans "Company settings" %}</h2>
85
85
</div>
86
86
</div>
87
87
</form>
88
-
89
-
{# ── Ask Cairn: semantic search index ──────────────── #}
90
-
<divclass="row">
91
-
<divclass="col-lg-8">
92
-
<divclass="card mb-4">
93
-
<divclass="card-header"><h6class="mb-0"><iclass="bi bi-stars me-2" style="color:var(--accent)"></i>{% trans "Semantic search index" %}</h6></div>
94
-
<divclass="card-body">
95
-
{% if not semantic.enabled %}
96
-
<pclass="text-muted mb-0">{% trans "Semantic search is disabled." %} {% trans "Enable it with the AI_ASSISTANT_SEMANTIC_ENABLED setting to let topic questions match requirements across languages." %}</p>
97
-
{% elif not semantic.embeddings_supported %}
98
-
<pclass="text-muted mb-0"><iclass="bi bi-exclamation-triangle me-1"></i>{% trans "The current AI provider has no embeddings, so the semantic index cannot be built. Use the Mistral, OpenAI or Ollama provider to index requirements." %}</p>
99
-
{% else %}
100
-
<divclass="row g-3 mb-3">
101
-
<divclass="col-sm-4">
102
-
<divclass="form-label mb-0">{% trans "Indexed requirements" %}</div>
<pclass="text-muted mb-3"><spanclass="spinner-border spinner-border-sm me-2"></span>{% trans "An update is currently running." %}</p>
116
-
{% endif %}
117
-
<pclass="text-muted small mb-3">{% trans "New and edited requirements are picked up automatically (daily and at startup); use this button to refresh immediately, e.g. after a bulk import." %}</p>
<divclass="card-header"><h6class="mb-0"><iclass="bi bi-stars me-2" style="color:var(--accent)"></i>{% trans "Semantic search index" %}</h6></div>
13
+
<divclass="card-body">
14
+
{% if not semantic.enabled %}
15
+
<pclass="text-muted mb-0">{% trans "Semantic search is disabled." %} {% trans "Enable it with the AI_ASSISTANT_SEMANTIC_ENABLED setting to let topic questions match requirements across languages." %}</p>
16
+
{% elif not semantic.embeddings_supported %}
17
+
<pclass="text-muted mb-0"><iclass="bi bi-exclamation-triangle me-1"></i>{% trans "The current AI provider has no embeddings, so the semantic index cannot be built. Use the Mistral, OpenAI or Ollama provider to index requirements." %}</p>
18
+
{% else %}
19
+
<divclass="row g-3 mb-3">
20
+
<divclass="col-sm-4">
21
+
<divclass="form-label mb-0">{% trans "Indexed requirements" %}</div>
<pclass="text-muted mb-3"><spanclass="spinner-border spinner-border-sm me-2"></span>{% trans "An update is currently running." %}</p>
35
+
{% endif %}
36
+
<pclass="text-muted small mb-3">{% trans "New and edited requirements are picked up automatically (daily and at startup); use this button to refresh immediately, e.g. after a bulk import." %}</p>
Copy file name to clipboardExpand all lines: docs/installation.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -140,7 +140,7 @@ Both accept `--dry-run` to preview changes. A typical host cron entry:
140
140
20 2 * * * cd /opt/cairn && docker compose exec -T web python manage.py mark_overdue_treatment_plans
141
141
```
142
142
143
-
If the **semantic search** of the Ask Cairn assistant is enabled (`AI_ASSISTANT_SEMANTIC_ENABLED`), schedule the index refresh the same way. The command is idempotent (it only re-embeds changed requirements and prunes deleted ones), so a daily run is cheap. The index is also refreshed automatically when the app starts, a deleted requirement is pruned immediately, and an administrator can force a refresh from the Company settings page; the daily cron is the reliable, self-healing backstop.
143
+
If the **semantic search** of the Ask Cairn assistant is enabled (`AI_ASSISTANT_SEMANTIC_ENABLED`), schedule the index refresh the same way. The command is idempotent (it only re-embeds changed requirements and prunes deleted ones), so a daily run is cheap. The index is also refreshed automatically when the app starts, a deleted requirement is pruned immediately, and an administrator can force a refresh from the **Administration -> Semantic index** page; the daily cron is the reliable, self-healing backstop.
144
144
145
145
```cron
146
146
25 2 * * * cd /opt/cairn && docker compose exec -T web python manage.py rebuild_semantic_index
Copy file name to clipboardExpand all lines: docs/modules/assistant/README.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -206,7 +206,7 @@ The index drifts as requirements are created, edited or deleted, so it is refres
206
206
207
207
-**On delete (immediate)**: a `post_delete` signal on `Requirement` (`assistant/signals.py`, wired from `AssistantConfig.ready()`) prunes the requirement's `SemanticIndex` row. This is a network-free DB delete, safe even when semantic search is disabled.
208
208
-**On startup**: when a server process boots (uvicorn / `runserver`) with the feature on, `AssistantConfig.ready()` launches a guarded background thread that runs the rebuild once (skipped for management commands like `migrate`/`test`, so the work never blocks boot and a slow provider can't wedge startup).
209
-
-**On demand (admin)**: the Company settings page (in-app Administration, gated by `system.config.update`) shows index status (indexed / total requirements, last updated, embedding model) and an **"Update the index now"** button that triggers a background rebuild (`assistant:rebuild-semantic-index`). The card warns when the active provider has no embeddings (e.g. `anthropic`).
209
+
-**On demand (admin)**: a dedicated **Administration -> Semantic index**page (`assistant:semantic-index`, sidebar link shown when `AI_ASSISTANT_ENABLED` and the user has `system.config.read`) shows index status (indexed / total requirements, last updated, embedding model) and an **"Update the index now"** button (gated by `system.config.update`) that triggers a background rebuild. It warns when the active provider has no embeddings (e.g. `anthropic`).
210
210
-**Scheduled (recommended backstop)**: run `manage.py rebuild_semantic_index` from cron (see [installation.md](../../installation.md)). It is the reliable, self-healing mechanism - it catches anything the others missed (e.g. an edit that no rebuild has run for yet, or an embed that failed transiently).
211
211
212
212
A cache lock (`assistant.semantic.rebuild_index_async`) dedupes overlapping triggers (startup + button + a double click), and the startup/admin rebuilds run in daemon threads that close their own DB connections. New and edited requirements become searchable at the next rebuild (startup, daily cron, or the admin button) - lexical search covers them immediately in the meantime.
0 commit comments