Skip to main content

Nox / Knox Admin

Audience: Ops · Super-admins · Support · Engineering · Where in app: /admin/knox/* · Access: Super-admin only (verify — these are admin-portal routes behind the admin layout; the ms-ai knowledge/model/feedback endpoints are the super-admin management surface).

Naming note: Nox is the product name shown to users; Knox is the internal/code name. The admin routes and ms-ai modules use knox, the UI labels say "Nox". They are the same assistant.

These screens are the back office for the Nox assistant: read every conversation, triage thumbs-down feedback, pick which AI model powers each Nox role, author the knowledge documents that feed Nox's RAG retrieval, register the portal pages Nox can navigate users to, watch/cancel per-visitor auto-engage directives, and sync Nox's tool registry to the shared ElevenLabs voice agent.

What it does

  • Conversations browser — cross-tenant list of Nox threads with per-turn tool-call audit logs and voice-call playback.
  • Feedback review — paginated rated turns (defaults to not_helpful) for debugging answer quality.
  • AI Models — map each Nox role (chat / narration / embedding / transcript enrichment) to a catalog (provider, model_id); exactly one default per role.
  • Knowledge authoring — collections + markdown documents that get chunked and embedded into the RAG store (knox_knowledge_chunks).
  • Page Registry — the catalog of portal pages Nox knows about, used by the navigation agent.
  • Visitor Watches — cross-company view + cancel of per-visitor notify / auto-engage directives, now with fire diagnostics.
  • Voice Tools — idempotent sync of the Nox tool registry into the shared ElevenLabs agent.
  • Nox Funnel audit — cross-company funnel audit-log browser + per-contact trace, plus backfill triggers (see Nox Funnel).
  • Beta gatesnox_funnel_beta_enabled and agent_k_beta_enabled toggles live on the company detail screen (views/admin/companies/Detail.vue), not under /admin/knox.

How it works

The Vue views live in frontend/src/views/admin/knox/ and the visitor-watch view in frontend/src/views/admin/visitor-watches/. Most knox screens call ms-ai directly via config.getAiApiUrl() (repository frontend/src/repositories/admin/knox.js), under /knox-agent/* and /knox-voice/*. Visitor Watches instead talk to the Node backend admin routes (frontend/src/repositories/admin/visitor-watches.js/admin/visitor-watches*).

ms-ai controllers:

  • knox-admin.controller.tscrm-backfill, models CRUD/default, conversations list+thread, feedback list (under knox-agent/admin/…).
  • knox-management.controller.ts — knowledge chunks, sources, pages, ingest, reembed (under knox-agent/knowledge/…).
  • knox-document.controller.ts — collections + documents + page-options (under knox-agent/documents/…).
  • knox-voice.controller.ts — voice call metadata/audio (knox-voice/calls/:thread_id) and the tool sync.

Knowledge documents are the authored source of truth; on save the document service (ms-ai/.../services/knox-document.service.ts) deletes the doc's old chunks, splits the markdown into semantic chunks, generates contextual embeddings, and stores them as knox_knowledge_chunks — that chunk table is what Nox actually retrieves at answer time.

Screens & fields

Conversations — /admin/knox/conversations

Source: KnoxConversations.vuegetKnoxConversations (GET /knox-agent/admin/conversations). One row per thread_id. Defaults to the last 7 days server-side; max window 90 days.

FilterNotes
From / Todate window
Company IDoptional — omit for cross-tenant browsing
ColumnMeaning
Latestmost recent turn time
Companytenant
Last questionthe visitor's latest question
Agentrouted sub-agent
Intentprimary intent
Turnsturn count
Toolstool-call count
Tokenstoken usage
Latencyresponse latency

Clicking a row opens KnoxConversationModal.vuegetKnoxConversationThread (…/conversations/threads/:thread_id), which renders the whole thread chronologically with each turn's tool_calls (input / output / duration) inline, plus per-turn feedback notes. Each tool call also shows "Model saw (markdown)" — the curated markdown the LLM actually read (model_markdown, rendered by ms-ai knox-tool-markdown.ts and persisted per turn), with an honest truncation marker when the stored output was capped at 24KB; the copy-to-markdown export includes it fenced. For voice threads it also calls getKnoxVoiceCall (GET /knox-voice/calls/:thread_id) for the ElevenLabs summary, termination reason, duration, and audio_available; if audio exists, fetchKnoxVoiceAudioBlob pulls the recording as a blob (auth header can't ride a bare <audio src>) for playback. Audio returns 404 if deleted from ElevenLabs retention, 403 if the admin doesn't own the call.

Feedback — /admin/knox/feedback

Source: KnoxFeedback.vuegetKnoxFeedback (GET /knox-agent/admin/feedback). Paginated rated turns; the debug case (not_helpful) is the default, but helpful is also supported. Filters: From/To, Company ID, sentiment. Each row shows: question, answer, the feedback badge (Helpful / Not helpful), routed_agent, primary_intent, feedback_note, thread_id, company_id, created_at.

AI Models — /admin/knox/models

Source: KnoxModels.vuegetKnoxModels / createKnoxModel / updateKnoxModel / setKnoxModelDefault / deleteKnoxModel (/knox-agent/admin/models). Maps Knox roles to a (provider, model_id) in the shared ai_models catalog. Exactly one model per role is the active default. This page only attaches a catalog model to a role — pricing/catalog itself lives elsewhere (Cost Tracking → Models).

Roles (create dropdown): Chat (answers, ingestion, context), Narration (recording analysis), Embedding, Transcript enrichment.

ColumnField
Modeldisplay_name / model id
Providerprovider
Selectedis_default (the active model for the role)
Actionsedit / set default / delete

Create flow: pick role → pick a catalog model from the dropdown (eligibleCatalogModels, filtered by role) → provider/model_id auto-fill → optional display name. Backing entity: knox_ai_models (provider, model_id, display_name, role, is_active, is_default); a unique constraint enforces one (provider, model_id, role) and a partial index enforces one default per role.

Knowledge — /admin/knox (collections + documents)

Source: KnoxKnowledge.vuegetKnoxCollectionTree / getKnoxDocuments / createKnoxCollection etc. (/knox-agent/documents/…). Left rail is the collection tree; main pane lists documents in the selected collection (or "All Documents") with a title/content/tag search and Bulk Import (KnoxBulkImportModal.vue) + New Document.

Collections (knox_knowledge_collections): name, slug (unique), description, icon, parent_id (nestable), sort_order, document_count, is_active. A collection with documents can't be hard-deleted (FK RESTRICT); soft-delete via is_active=false.

Document editor — /admin/knox/doc/new, /admin/knox/doc/:id

Source: KnoxDocEditor.vuegetKnoxDocument / saveKnoxDocument / deleteKnoxDocument (/knox-agent/documents). Markdown authoring surface. Editing/saving a document re-chunks and re-embeds it into the RAG store.

Document entity (knox_knowledge_documents):

FieldNotes
title
markdown_contentfull markdown source
content_typefeature_guide (default) · how_to · troubleshooting · policy · api_reference · pricing · glossary
product_areaintegrations, billing, chat, …
plan_scopeall (default) · starter · growth · pro · enterprise
tags[]
related_urls[]portal page URLs this doc covers (picker fed by getKnoxPageOptions/knox-agent/documents/page-options) — rendered as inline links in answers
collectionrequired FK — every doc belongs to one collection, no orphans
statusdraft · processing · published · failed
chunk_counthow many chunks were generated
processing_error, last_processed_at, author_id, version, is_activeprocessing/authoring metadata

The resulting chunks (knox_knowledge_chunks) carry content, context, feature_area, content_type, keywords[], requires_role, difficulty, two 1536-dim vector embeddings, and is_active. Admins can also browse/edit chunks directly via getKnoxChunks / updateKnoxChunk and trigger reembedAllKnoxChunks (POST /knox-agent/knowledge/reembed).

Page Registry — /admin/knox/pages, …/pages/create, …/pages/:id/edit

Source: knox/pages/List.vue + knox/pages/Edit.vuegetKnoxPages / createKnoxPage / updateKnoxPage / deleteKnoxPage / seedKnoxPages (/knox-agent/knowledge/pages). The catalog of portal pages Nox's navigation agent can route users to.

List filters: search (URL/title/section/role), feature area, status (All / Active only / Inactive only). List columns: Page, URL Pattern, Feature Area, Role, Status, Actions.

Edit form (entity knox_page_registry):

FieldNotes
url_patternunique — e.g. /settings/integrations/shopify
title
feature_areapick or type
Breadcrumb / parent_urle.g. Settings > Integrations > Shopify / /settings/integrations
requires_rolepublic · user · admin (default) · agency
description
keywords / aliasessearch/intent matching for navigation
UI Elementsjsonb list of {id, label, type} where type ∈ input / button / toggle / select / link / section

Visitor Watches — /admin/knox/visitor-watches

Source: visitor-watches/Index.vuegetVisitorWatches / cancelVisitorWatch / getVisitorWatchEvents (Node backend /admin/visitor-watches*). Cross-company view of per-visitor Nox watch / auto-engage directives, plus a fired-events history sub-tab.

Directives filters: Status (active / done / expired / All), Type (notify / auto_engage / All), Company ID. Directive columns: Company, Person, Type, Recurrence, Confidence, Set by, Status, Last fired, Created, Actions (Cancel → DELETE /admin/visitor-watches/:id).

A Diagnostics column (admin-only — not rendered on the tenant list) explains why an active directive keeps not-firing: last_attempt_at, attempt_count, and last_skip_reason (tooltip "Matched N× — last match skipped: …"). Fields live on KnoxVisitorDirectiveModel and are stamped by PersonWatchService on every recognition attempt. Tenants have their own list/cancel surface (Settings → Nox, GET/DELETE /knox/visitor-watches).

Events history (survives the directive): filter by Company ID, Type (notify / auto_engage), Outcome (fired / fire_failed).

Nox Funnel audit — /admin/nox-funnel/*

Source: views/admin/nox-funnel/AuditLogs.vue + ContactTrace.vue (repository repositories/admin/noxFunnel.js) → Node backend GET /admin/nox-funnel/audit-logs and GET /admin/nox-funnel/contacts/trace (AdminNoxFunnelController). Browses the 120-day nox_funnel_audit_logs trail (signals, dedupes, gates, stage flips, intercept throttles) cross-company, and traces one contact's full funnel history. Manual triggers: POST /admin/nox-funnel/backfill (seed a newly-gated tenant), /brief-send-hour-backfill (9→5 cohort), /reason-text-backfill.

Voice Tools — /admin/knox/voice-tools

Source: KnoxVoiceTools.vue. Sync to ElevenLabs reads every tool registered in KnoxToolRegistry on ms-ai and mirrors it into the ElevenLabs workspace: new tools are created, existing tools updated (latest schema + webhook URL), removed tools deleted, and the shared "Knox" agent is upserted to point at the resulting tool set. Idempotent — safe to re-run, intended after editing the tool registry or a fresh deploy. The result panel reports the agent action + id, attached tool count, and created/updated/deleted counts (or a failure message). This is a registry-sync view, not a per-tool editor.

Behaviors & edge cases

  • Nox vs Knox is a naming split, not two systems.
  • Saving a knowledge document re-chunks and re-embeds it — old chunks for that doc are deleted first, so a save is a full reprocess (status moves through processing; failed + processing_error on error).
  • Exactly one default model per rolesetKnoxModelDefault flips the active model; deleting the default for a role needs another model promoted.
  • Conversations default to 7 days, max 90 — widen From/To to look further back.
  • Voice audio is retention-bound404 once ElevenLabs has purged the recording; 403 if the admin doesn't own the call.
  • CRM-link backfill (backfillCrmLinksPOST /knox-agent/admin/crm-backfill) re-syncs knox_visitor_profiles.ghl_contact_id from the backend source of truth, fixing CRM-linked / pipeline-stage metrics that undercount because the mirror only learns links reactively from GHL stage webhooks.

Technical implementation

  • Frontend: frontend/src/repositories/admin/knox.js, frontend/src/repositories/admin/visitor-watches.js; views under frontend/src/views/admin/knox/ and frontend/src/views/admin/visitor-watches/.
  • ms-ai controllers: knox-admin.controller.ts, knox-management.controller.ts, knox-document.controller.ts, knox-voice.controller.ts.
  • ms-ai entities: knox-knowledge-document.entity.ts, knox-knowledge-collection.entity.ts, knox-knowledge-chunk.entity.ts, knox-page-registry.entity.ts, knox-ai-model.entity.ts.
  • Doc → chunk pipeline: ms-ai/src/knox-agent/services/knox-document.service.ts; retrieval: knox-knowledge.service.ts.
  • Voice tool sync: ms-ai/src/knox-voice/knox-agent-sync.service.ts, knox-voice-tools.service.ts, knox-voice-registry.store.ts.
  • Backend visitor-watch routes: backend/app/routes/adminVisitorWatchRoutes.js; funnel admin routes: backend/app/routes/adminNoxFunnelRoutes.js.
  • Beta toggles: PUT /company/:_id/nox-funnel-beta (also sets knox.daily_brief.send_hour 9→5) and PUT /company/:_id/agent-k-beta (CompanyController), surfaced on views/admin/companies/Detail.vue.