The Nia Advisor
Retrieval-grounded answering over a fund's knowledge: retrieval, grounding, refusals, citations, and conversation persistence.
The Nia Advisor answers questions using only the knowledge indexed for a tenant. It retrieves the
most relevant chunks, grounds an answer in them with citations, refuses when the corpus doesn't
support an answer, and saves the exchange as a conversation. It is implemented in @repo/advisor,
with retrieval in @repo/rag and model access in @repo/ai.
What it does for users
- Grounded answers. Responses come from the fund's indexed documents and the shared global playbook, not from the model's general knowledge.
- Citations. Answers reference the source chunks they used.
- Honest refusals. If the knowledge base doesn't contain the answer, the advisor says so and points the user to the Nia team instead of guessing.
- Knowledge-gap signals. When an answer leans on thin or weak organization context, the turn is flagged so operators can see where the corpus needs work.
- Conversations. Each thread is saved with its messages and citations, so users can return to earlier answers and operators can review them.
Answer flow
Retrieval scope
Retrieval is tenant- and plan-aware (@repo/rag):
| Plan | Corpus searched |
|---|---|
bot_only | The global playbook only. |
policy_hub, full | The organization's own documents plus the global playbook. |
Searches run as approximate-nearest-neighbour queries against the HNSW vector index, filtered to indexed, non-superseded documents in the allowed scope. Only chunks the tenant is permitted to see are considered.
Grounding and refusals
The advisor refuses rather than answering beyond the evidence. A turn is refused when retrieval
returns nothing relevant enough, measured by a minimum relevance threshold and a minimum count of
sufficiently relevant chunks. The grounding prompt also tells the model to reply with a fixed refusal
message when the context doesn't contain the answer, and the system normalizes any model output that
drifts toward a refusal into that exact message. Refused assistant messages are stored with
refused = true, which feeds the operator Knowledge Gaps view.
Knowledge-gap detection
Beyond outright refusals, the retrieval layer flags a turn as a knowledge gap when the organization's own context is thin, or noticeably weaker than the global playbook for the question. When that happens, global content is favoured in ranking and the turn carries a gap flag. This shows which tenants and topics need a stronger org corpus.
Conversation persistence
Conversations and messages are stored per organization:
- A
conversationrecords the channel (weborwhatsapp), the owning user (for web), a title, and a retention horizon. - Each
messagestores its role, content, citations, refusal flag, the model used, and token counts.
Web conversations are owner-scoped, so a user can only open their own threads, while platform operators can review any conversation through the Command Center. Recent prior messages are included as context on each new turn so multi-turn threads stay coherent.
Usage and cost
Every advisor turn writes an aiUsageLog entry (organization, user, channel, kind = 'advisor',
model, tokens in/out) and increments the organization's monthly usageCounter. The usage-cap
middleware checks the counter against the plan's run cap before spending, so a tenant can't exceed
its plan. Operators see this rolled up under
Intelligence.