Aug 7 - Update: knowledge base MT19

This commit is contained in:
2026-08-07 17:32:43 -04:00
parent 38ab66d021
commit 3c35835505
6 changed files with 276 additions and 2 deletions
+5
View File
@@ -69,6 +69,11 @@ class SupportKnowledge(db.Model):
title = db.Column(db.String(200), nullable=False)
body = db.Column(db.Text, nullable=False)
active = db.Column(db.Boolean, default=True, nullable=False)
# MT-19 — admin-controlled ordering. Entries are injected into the support
# chat's system prompt in this order, so a low sort_order is how an admin
# promotes the guidance the assistant should reach for first. Ties break on
# id, keeping the order stable.
sort_order = db.Column(db.Integer, nullable=False, default=0)
created_by = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='SET NULL'), nullable=True)
created_at = db.Column(db.DateTime, default=now_eastern, nullable=False)
updated_at = db.Column(db.DateTime, default=now_eastern, nullable=False)
+28 -2
View File
@@ -91,7 +91,9 @@ FAQS = [
def _system_prompt_with_kb():
"""Return the Groq system prompt, appending active knowledge base entries."""
try:
entries = SupportKnowledge.query.filter_by(active=True).order_by(SupportKnowledge.id).all()
entries = (SupportKnowledge.query.filter_by(active=True)
.order_by(SupportKnowledge.sort_order.asc(),
SupportKnowledge.id.asc()).all())
except Exception:
return _SYSTEM_PROMPT
if not entries:
@@ -516,10 +518,31 @@ def admin_conversation_detail(session_id):
@login_required
@supervisor_required
def admin_knowledge():
entries = SupportKnowledge.query.order_by(SupportKnowledge.created_at.desc()).all()
# Same order the chat prompt uses, so the admin list shows the real
# priority rather than a different one.
entries = (SupportKnowledge.query
.order_by(SupportKnowledge.sort_order.asc(),
SupportKnowledge.id.asc()).all())
return render_template('support/admin_knowledge.html', entries=entries)
def _parse_sort_order(raw, fallback=0):
"""Coerce a submitted sort_order to a sane int.
The column is NOT NULL, so a blank or non-numeric field must not reach the
DB. Clamped to 0..9999 to match the range ST validates, and falls back to
the existing value on edit so a blank field means "leave it alone" rather
than silently resetting the entry to the top.
"""
raw = (raw or '').strip()
if not raw:
return fallback
try:
return max(0, min(9999, int(raw)))
except (TypeError, ValueError):
return fallback
@bp.route('/admin/knowledge/add', methods=['POST'])
@login_required
@supervisor_required
@@ -534,6 +557,7 @@ def admin_knowledge_add():
title = title,
body = body,
active = True,
sort_order = _parse_sort_order(request.form.get('sort_order')),
created_by = current_user.id,
created_at = now_eastern(),
updated_at = now_eastern(),
@@ -561,6 +585,8 @@ def admin_knowledge_edit(entry_id):
return redirect(url_for('support.admin_knowledge_edit', entry_id=entry_id))
entry.title = title
entry.body = body
entry.sort_order = _parse_sort_order(request.form.get('sort_order'),
entry.sort_order)
entry.updated_at = now_eastern()
db.session.commit()
log_action(ACTION_UPDATE, 'SupportKnowledge', entry.id, title[:60], 'edited')
@@ -34,6 +34,12 @@
placeholder="Add facts, FAQs, or instructions the AI should know about this customer's account…"></textarea>
<div class="form-text">Keep entries focused and factual. Combined active entries are capped at 6,000 characters.</div>
</div>
<div class="mb-3" style="max-width:200px;">
<label class="form-label fw-semibold">Sort Order</label>
<input type="number" name="sort_order" class="form-control"
min="0" max="9999" step="1" value="0">
<div class="form-text">Lower numbers are sent to the assistant first. Leave at 0 unless an entry should take priority.</div>
</div>
<button type="submit" class="btn btn-primary btn-sm">
<i class="bi bi-plus me-1"></i>Add Entry
</button>
@@ -54,6 +60,7 @@
<div class="d-flex justify-content-between align-items-start">
<div class="flex-grow-1 me-3">
<div class="d-flex align-items-center gap-2 mb-1">
<span class="badge bg-light text-dark border" title="Sort order">#{{ entry.sort_order }}</span>
<span class="fw-semibold">{{ entry.title }}</span>
{% if entry.active %}
<span class="badge bg-success">Active</span>
@@ -23,6 +23,12 @@
<textarea name="body" class="form-control" rows="8" required>{{ entry.body }}</textarea>
<div class="form-text">Combined active entries are capped at 6,000 characters in the AI prompt.</div>
</div>
<div class="mb-3" style="max-width:200px;">
<label class="form-label fw-semibold">Sort Order</label>
<input type="number" name="sort_order" class="form-control"
min="0" max="9999" step="1" value="{{ entry.sort_order }}">
<div class="form-text">Lower numbers are sent to the assistant first. Leave at 0 unless an entry should take priority.</div>
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">
<i class="bi bi-check-lg me-1"></i>Save Changes