Docs: update

This commit is contained in:
2026-05-04 15:34:51 -04:00
parent be71709608
commit 705b4f8cbe

View File

@@ -1,102 +1,142 @@
# Mnemosyne Integration — Pallas Reference # Mnemosyne Integration — Pallas Reference
This document summarises the Pallas-specific changes required for Mnemosyne knowledge integration. The full specification lives in [`daedalus/docs/mnemosyne_integration.md`](../../daedalus/docs/mnemosyne_integration.md). This document describes how Pallas-hosted agents connect to Mnemosyne for workspace-scoped knowledge search. The full integration specification lives in [`daedalus/docs/mnemosyne_integration.md`](../../daedalus/docs/mnemosyne_integration.md).
--- ---
## Overview ## Overview
Pallas agents gain access to Mnemosyne's content-type-aware knowledge graph as a downstream MCP server. Agents can search documents, browse libraries, retrieve items, and traverse the concept graph — all via standard MCP tool calls. Mnemosyne is a downstream MCP server like any other from Pallas's perspective. Agents declare `"mnemosyne"` in their `servers` list; the server URL and bearer-forward opt-in live in the project's `fastagent.config.yaml`.
What makes Mnemosyne different from other downstream servers:
- **Workspace-scoped search.** Daedalus mints a per-turn HS256 JWT carrying the workspace UUID and sends it as `Authorization: Bearer` on the `send_message` call to Pallas. Pallas captures it in `request_bearer_token`, and the fast-agent patch (`pallas._fastagent_patch`) forwards it on outgoing calls to Mnemosyne when `forward_inbound_auth: true` is set. Mnemosyne validates the JWT and scopes all Cypher searches to that workspace.
- **The LLM never sees `workspace_id`.** The scoping is claim-driven: Mnemosyne reads the JWT claims, overwrites any `workspace_id` the model may have produced in tool arguments, and enforces containment server-side. Pallas is transparent transport.
--- ---
## Configuration Changes ## Configuration
### fastagent.config.yaml ### fastagent.config.yaml
Add the Mnemosyne MCP server: Add the `mnemosyne` stanza to `mcp.servers`. The only Mnemosyne-specific flag is `forward_inbound_auth: true`:
```yaml ```yaml
mcp: mcp:
servers: servers:
# ... existing servers (argos, neo4j_cypher, kernos, rommie, gitea, grafana) ...
mnemosyne: mnemosyne:
transport: http transport: http
url: "http://puck.incus:22091/mcp" url: "https://mnemosyne.ouranos.helu.ca/mcp/"
forward_inbound_auth: true
``` ```
This is already deployed in `iolaus/fastagent.config.yaml`, `kottos/fastagent.config.yaml`, and `mentor/fastagent.config.yaml` and their Ansible templates in `virgo/ansible/`.
### Agent Definitions ### Agent Definitions
#### Research Agent (port 23031) Add `"mnemosyne"` to the `servers` list of any agent that should be able to search workspace content. Sub-agents (e.g. `research`, `tech_research`) that are orchestrated by primary agents do not need it unless they independently issue search calls.
The `knowledge` agent in the research chain gains Mnemosyne access: **iolaus** — all primary agents have Mnemosyne access: `shawn`, `david`, `hypatia`, `watson`, `nate`, `garth`, `bourdain`, `cousteau`, `marcus`, `cristiano`, `mikael`.
**kottos**`harper`, `scotty`.
**mentor**`alan`, `ann`, `jeffrey`, `jarvis`, `aws_sa`.
Example (from `iolaus/agents/shawn.py`):
```python ```python
@fast.agent(name="search", servers=["argos"]) @fast.agent(
@fast.agent(name="knowledge", servers=["neo4j_cypher", "mnemosyne"]) name="shawn",
@fast.chain(name="research", sequence=["search", "knowledge"], default=True) instruction=_INSTRUCTION,
servers=["argos", "mnemosyne", "neo4j_cypher", "kernos", "time"],
default=True,
)
async def _shawn():
pass
``` ```
The `knowledge` agent's system instruction should guide tool selection: ---
> Use `mnemosyne.search_knowledge` for document content retrieval — it handles chunking, vector search, re-ranking, and content-type-aware context. Use `neo4j_cypher` for graph topology queries, relationship exploration, and data not managed by Mnemosyne. ## How Bearer Forwarding Works
#### Infrastructure Agent (port 23032)
No changes — Infrastructure does not use Mnemosyne.
#### Orchestrator (port 23033)
```python
@fast.agent(name="research_sub", servers=["argos", "neo4j_cypher", "mnemosyne"])
@fast.agent(name="infra_sub", servers=["kernos", "gitea", "rommie"])
@fast.orchestrator(name="orchestrator", agents=["research_sub", "infra_sub"],
plan_type="iterative", default=True)
```
### Registry Update
Update agent descriptions to reflect Mnemosyne access:
1. Daedalus mints a per-turn JWT:
```json ```json
{ {
"server": { "iss": "daedalus",
"name": "ca.helu.ouranos/pallas-research", "sub": "chat",
"title": "Research Agent", "ws": "<workspace_uuid>",
"description": "Web search via Argos, knowledge graph via Neo4j, and content library search via Mnemosyne", "libs": [],
"version": "1.1.0", "iat": <now>,
"remotes": [ "exp": <now + 600>,
{ "type": "streamable-http", "url": "http://puck.incus:23031/mcp" } "jti": "<uuid4>"
]
}
} }
``` ```
2. Daedalus calls Pallas's `send_message` tool with `Authorization: Bearer <token>` in the HTTP request headers.
3. Pallas's `MultimodalAgentMCPServer` captures the token via FastMCP's `get_access_token()` into the `request_bearer_token` context variable (see `pallas/multimodal_server.py`).
4. The fast-agent patch in `pallas/_fastagent_patch.py` (installed at import time in `pallas/__init__.py`) wraps `_prepare_headers_and_auth`. When a server config has `forward_inbound_auth: true`, the patch reads `request_bearer_token.get()` and injects `Authorization: Bearer <token>` into the outgoing HTTP headers for that MCP call.
5. Mnemosyne receives the same token, validates the HMAC signature against its `MCPSigningKey` table, and scopes all search Cypher queries to `ws` from the claims.
The `forward_inbound_auth` flag is **per-server** — other servers in the same agent (`argos`, `neo4j_cypher`, `time`, etc.) never receive the bearer.
--- ---
## Available Mnemosyne MCP Tools ## Available Mnemosyne MCP Tools
These tools become available to agents with `mnemosyne` in their `servers` list: These tools become available to agents with `"mnemosyne"` in their `servers` list:
| Tool | Purpose | When to Use | | Tool | Purpose |
|------|---------|-------------| |------|---------|
| `search_knowledge` | Hybrid vector + full-text + graph search with re-ranking | Document content retrieval, question answering over stored knowledge | | `search_knowledge` | Hybrid vector + full-text + graph search with re-ranking, scoped to the current workspace |
| `search_by_category` | Search scoped to a library type (fiction, technical, etc.) | When the user specifies or implies a content domain | | `search_by_category` | Search within a specific library type (technical, fiction, business, etc.) |
| `list_libraries` | List all knowledge libraries | Discovering what knowledge domains exist | | `list_libraries` | List accessible libraries |
| `list_collections` | List collections within a library | Browsing a specific knowledge domain | | `list_collections` | List collections within a library |
| `get_item` | Retrieve item metadata + chunk previews + concept links | Deep dive on a specific document/item | | `get_item` | Retrieve item metadata, chunk previews, and concept links |
| `get_concepts` | Traverse concept graph | Exploring relationships between topics, people, places | | `get_concepts` | Traverse the concept graph |
All tools are transparently scoped to the workspace by JWT claims. An agent in workspace A cannot retrieve content from workspace B regardless of what arguments it produces.
--- ---
## Downstream MCP Servers (Updated) ## Downstream MCP Servers
| Server | Host | URL | Used by | | Server | URL | `forward_inbound_auth` |
|--------|------|-----|---------| |--------|-----|----------------------|
| argos | miranda.incus | `http://miranda.incus:25534/mcp` | Research, Orchestrator | | mnemosyne | `https://mnemosyne.ouranos.helu.ca/mcp/` | `true` |
| neo4j_cypher | circe.helu.ca | `http://circe.helu.ca:22034/mcp` | Research, Orchestrator | | argos | `http://miranda.incus:25534/mcp` | |
| **mnemosyne** | **puck.incus** | **`http://puck.incus:22091/mcp`** | **Research, Orchestrator** | | neo4j_cypher | `http://circe.helu.ca:22034/mcp` | — |
| kernos | caliban.incus | `http://caliban.incus:22021/mcp` | Infrastructure, Orchestrator | | kernos | `http://caliban.incus:22021/mcp` | |
| gitea | miranda.incus | `http://miranda.incus:25535/mcp` | Infrastructure, Orchestrator | | gitea | `http://miranda.incus:25535/mcp` | |
| rommie | caliban.incus | `http://caliban.incus:22031/mcp` | Infrastructure, Orchestrator | | rommie | `http://caliban.incus:22031/mcp` | |
| grafana | miranda.incus | `http://miranda.incus:25533/mcp` | Infrastructure | | grafana | `http://miranda.incus:25533/mcp` | — |
---
## Provisioning (one-time, server-side)
1. On the Mnemosyne host, generate the signing key:
```bash
docker compose exec app python manage.py seed_signing_key --kid daedalus-1
# Copy the printed hex secret
```
2. Set on Daedalus (`.env` or Ansible vault):
```
DAEDALUS_MNEMOSYNE_MCP_URL=https://mnemosyne.ouranos.helu.ca/mcp/
DAEDALUS_MNEMOSYNE_SIGNING_KID=daedalus-1
DAEDALUS_MNEMOSYNE_SIGNING_SECRET=<hex from step 1>
DAEDALUS_MNEMOSYNE_TOKEN_TTL_SECONDS=600
```
3. Restart Daedalus and the three agent deployments (iolaus, kottos, mentor).
The OCI vault secret is `virgo-mnemosyne-signing-secret`; Ansible injects it via `mnemosyne_signing_secret`.
---
## Degraded Mode
If Daedalus's `MNEMOSYNE_SIGNING_SECRET` is blank or `MNEMOSYNE_MCP_URL` is empty, `mint_chat_token` returns `None`. Pallas calls proceed without a bearer; Mnemosyne search is unavailable but all other agent tools continue normally. No error is surfaced to the user.