Configuration
Namespaces & Persona
A namespace defines persona and behavior for the assistant inside a department. Each namespace owns its system prompt, formality scale, escalation rules, and trust matrix.
Persona Configuration
The persona JSON field supports:
{
"language": "uk",
"style": {
"verbosity": "concise",
"citations": true,
"structure": "bullets",
"formality": 80
},
"boundaries": ["Do not provide legal advice", "Redirect medical questions to HR"],
"escalation": {
"triggers": ["lawsuit", "termination", "complaint"],
"defaultAssignee": "<user-id>",
"message": "This question has been escalated to a specialist."
},
"greeting": "Hello! How can I help you today?",
"fallback": "I'm not sure about that. Let me connect you with a specialist."
}
Formality Scale
persona.style.formality is an integer from 0 to 100.
0-33— informal, plain-language responses34-66— balanced professional tone67-100— formal legal language
The deprecated persona.tone field is no longer accepted by the API.
System Prompt
systemPrompt is injected as the first message in the LLM context. Use it to set the assistant's role, constraints, and knowledge boundaries.
API
List Namespaces
GET /api/v1/namespaces
Create Namespace
POST /api/v1/namespaces
Body: { "name": "legal", "departmentId": "<id>", "systemPrompt": "...", "persona": {...} }
Update Namespace
PATCH /api/v1/namespaces/:id
Body: { "systemPrompt": "...", "persona": {...} }
Delete Namespace
DELETE /api/v1/namespaces/:id
Agent Runner Configuration
The agentRunner field in Namespace.config controls which adapter processes tasks for that namespace.
PATCH /api/v1/namespaces/:id
{
"config": {
"agentRunner": {
"activeAdapter": "api",
"adapters": {
"api": { "model": "gpt-4o-mini", "apiKey": "$OPENAI_API_KEY" },
"claude_local": { "model": "claude-sonnet-4-6", "maxTokens": 4096, "timeoutMs": 300000 },
"codex_local": { "model": "codex-mini-latest", "timeoutMs": 300000 },
"ollama": { "baseUrl": "http://localhost:11434", "model": "llama3.1-70b", "temperature": 0.7 }
}
}
}
}
| Field | Type | Description |
|---|---|---|
activeAdapter | api | claude_local | codex_local | ollama | Which adapter to use for this namespace |
adapters.<type> | object | Per-adapter settings (model, timeout, keys, etc.) |
Switching adapters is a single config update — no code changes.
Related Features
- Agent Runner — each namespace picks its adapter via
config.agentRunner.activeAdapter. - Intent Trust —
IntentTrustrecords are scoped bynamespaceId. - Intent Examples — training phrases are namespace-scoped.
- Conversations — each conversation can belong to a namespace.
- RAG — the namespace system prompt is injected into the RAG context.
Model Routes
AgentCore talks to OpenAI-compatible APIs for generation and embeddings. Routing is driven by environment variables.
LLM Generation
| Variable | Default | Description |
|---|---|---|
OPENAI_API_KEY | — | API key (required) |
OPENAI_BASE_URL | https://api.openai.com/v1 | Base URL for generation API |
OPENAI_MODEL | gpt-4o | Model used for RAG generation |
Alternative Providers
Any OpenAI-compatible API works — just change OPENAI_BASE_URL:
# Azure OpenAI
OPENAI_BASE_URL=https://your-resource.openai.azure.com/openai/deployments/gpt-4o
OPENAI_API_KEY=your-azure-key
# Local model (Ollama, vLLM, etc.)
OPENAI_BASE_URL=http://localhost:11434/v1
OPENAI_API_KEY=not-needed
OPENAI_MODEL=llama3
Embedding
| Variable | Default | Description |
|---|---|---|
OPENAI_EMBEDDING_MODEL | text-embedding-3-small | Embedding model (1536-dim) |
The embedding model must produce 1536-dimensional vectors to match the pgvector column. Swap models only if dimensions line up.
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL | yes | — | PostgreSQL connection string |
OPENAI_API_KEY | yes | — | OpenAI API key |
JWT_SECRET | yes | — | JWT signing secret, minimum 32 characters |
NODE_ENV | no | development | Runtime mode: development, production, or test |
PORT | no | 3000 | Server port |
HOST | no | 0.0.0.0 | Bind address |
REDIS_URL | no | redis://localhost:6379 | Redis connection string |
KB_UPLOAD_DIR | no | ./tmp/knowledge_uploads | Document upload directory |
OPENAI_BASE_URL | no | https://api.openai.com/v1 | LLM API base URL |
OPENAI_MODEL | no | gpt-4o | LLM model for generation |
OPENAI_EMBEDDING_MODEL | no | text-embedding-3-small | Embedding model |
ANTHROPIC_API_KEY | no | — | Anthropic API key, reserved for future routing |
LANGFUSE_PUBLIC_KEY | no | — | Langfuse tracing public key |
LANGFUSE_SECRET_KEY | no | — | Langfuse tracing secret key |
LANGFUSE_HOST | no | — | Langfuse server URL |
JWT_EXPIRES_IN | no | 7d | JWT token expiry |
PII_ENCRYPTION_KEY | yes | — | Base64-encoded 32-byte AES-GCM key |
WHATSAPP_APP_ID | no | — | WhatsApp Cloud API app ID |
WHATSAPP_APP_SECRET | no | — | WhatsApp Cloud API secret |
WHATSAPP_PHONE_NUMBER_ID | no | — | WhatsApp phone number ID |
WHATSAPP_ACCESS_TOKEN | no | — | WhatsApp API access token |
WHATSAPP_WEBHOOK_VERIFY_TOKEN | no | — | Webhook verification token |
WA_PHONE_NUMBER | no | +380000000000 | WhatsApp sender number |
WA_RATE_LIMIT_PER_MIN | no | 60 | WhatsApp messages per minute |
TG_BOT_TOKEN | no | — | Telegram bot token |
TG_RATE_LIMIT_PER_MIN | no | 30 | Telegram messages per minute |
ALLOWED_ORIGINS | no | http://localhost:5173 | Exact CORS allowed origins |
MEMORY_EXTRACT_EVERY_N_MESSAGES | no | 10 | Messages before memory extraction |
MEMORY_EXTRACTION_MODEL | no | gpt-4o-mini | Model for memory extraction |
INTENT_TRIGGER_WORDS | no | see config.ts | Comma-separated HITL trigger words |
Memory Extraction
| Variable | Default | Description |
|---|---|---|
MEMORY_EXTRACTION_MODEL | gpt-4o-mini | Model for employee profile extraction |
The default uses a smaller model — profile extraction is less quality-sensitive than RAG generation, so the cost savings are worth it.
Anthropic (Optional)
| Variable | Default | Description |
|---|---|---|
ANTHROPIC_API_KEY | — | Anthropic API key |
Reserved for future multi-provider routing. Not currently used in the main generation pipeline.
RAG Weights
Retrieval weights can be tuned per knowledge base to match different content types.
Default Weights
| Field | Default | Description |
|---|---|---|
vector | 0.65 | Share of the final score from vector (embedding) search |
keyword | 0.35 | Share of the final score from full-text keyword search |
Within the vector budget, 85% goes to chunk-content embeddings and 15% to synthetic Q&A embeddings. These fractions are fixed and not configurable. vector + keyword must sum to ≤ 1.0.
Per-KB Configuration
Set custom weights through the dedicated knowledge-base config endpoint:
PATCH /api/v1/knowledge/bases/:id/config
{
"ragWeights": {
"vector": 0.70,
"keyword": 0.30
}
}
Pass "ragWeights": null to remove per-KB weights and return to global defaults.
Tuning Guidelines
| Content Type | Recommendation |
|---|---|
| Legal documents (structured) | Higher keyword weight (e.g. keyword: 0.45) — legal terms are precise |
| FAQ / Q&A pairs | Higher vector weight (e.g. vector: 0.80) — semantic matching matters more |
| General text | Default weights work well |
| Technical documentation | Balanced — terms matter but context too |
How Scoring Works
- Each retrieval path returns candidates with raw scores.
- Scores are normalized per-path (0–1 range).
- Final score:
(vector × 0.85) × vecScore + (vector × 0.15) × qScore + keyword × keyScore. - Top 6 candidates win.