Per-Agent Knowledge Scoping
Each Octopus agent has its own isolated vector collection for semantic memory. Documents indexed for one agent cannot be retrieved by another agent — even within the same tenant. This prevents knowledge cross-contamination and enforces the principle of least knowledge.
Collection Naming Convention
// Collection name format
string GetCollectionName(AgentComposite agent) =>
$"agent_{agent.Id:N}_{agent.TenantId.Replace("-", "_")}";
// Example collection names:
// agent_5e7d3a1b0c8f4e2a9d6b7c5e3f1a2b4c_tenant_acmecorp
// agent_8a9f2e4c1b5d7f3e6a8c0d2b4f6e8a0c_tenant_acmecorp
// A Finance agent and HR agent in the same tenant have DIFFERENT collections:
// → Finance: agent_{financeId}_tenant_acmecorp
// → HR: agent_{hrId}_tenant_acmecorp
Shared Knowledge Collections
In some cases, multiple agents should share a common knowledge base (e.g., company-wide policies visible to all agents). This is supported via a shared collection that agents opt into:
// Shared collection configuration
public class SharedKnowledgeConfig
{
public bool UseSharedCollection { get; set; } = false;
public string? SharedCollectionName { get; set; } // tenant-scoped shared collection
public int SharedTopK { get; set; } = 2; // results from shared collection
// Total results = SemanticTopK (agent-specific) + SharedTopK (shared)
}
// Retrieval with shared collection
var agentResults = await _store.SearchAsync(agentCollection, queryEmbedding, topK: 5);
var sharedResults = config.UseSharedCollection
? await _store.SearchAsync(sharedCollection, queryEmbedding, topK: 2)
: Enumerable.Empty<MemoryRecord>();
var combined = agentResults.Concat(sharedResults).ToList();
Cross-Agent Access Prevention
The Octopus API enforces collection access. When an agent performs a semantic search, the collection name is derived from the agent's ID — not from any user-provided input. There is no API that allows specifying an arbitrary collection name at retrieval time:
// In SemanticMemoryService — collection is always derived from the agent, not from user input
public async Task<SemanticRetrievalResult> RetrieveAsync(
AgentComposite agent, // only the loaded agent can determine the collection
string query, CancellationToken ct)
{
// collection is derived from agent identity — cannot be overridden
var collection = GetCollectionName(agent); // e.g., "agent_5e7d..."
return await _store.SearchAsync(collection, ...);
// User input cannot change which collection is searched
}
The default is maximum isolation — each agent only searches its own collection. Shared access must be explicitly configured. This means a newly created agent starts with an empty knowledge base and cannot accidentally inherit knowledge from other agents.