Configuration¶
The gateway is configured via YAML files with environment variable expansion.
Config File Location¶
Set via environment variable:
Provider Configuration¶
Each primitive has a default provider and a backends map:
providers:
memory:
default: "in_memory" # Used when no override is specified
backends:
in_memory:
backend: "agentic_primitives_gateway.primitives.memory.in_memory.InMemoryProvider"
config: {}
mem0:
backend: "agentic_primitives_gateway.primitives.memory.mem0_provider.Mem0MemoryProvider"
config:
vector_store:
provider: milvus
config:
collection_name: agentic_memories
url: "http://${MILVUS_HOST:=localhost}:${MILVUS_PORT:=19530}"
llm:
provider: aws_bedrock
config:
model: us.anthropic.claude-sonnet-4-20250514-v1:0
embedder:
provider: aws_bedrock
config:
model: amazon.titan-embed-text-v2:0
Environment Variable Expansion¶
Use ${VAR:=default} syntax in YAML:
Per-Request Provider Routing¶
Clients can override which backend to use per-request via headers:
# Use mem0 for this specific request
curl -H "X-Provider-Memory: mem0" http://localhost:8000/api/v1/memory/ns
# Override all primitives
curl -H "X-Provider: agentcore" http://localhost:8000/api/v1/memory/ns
Credential Pass-Through¶
AWS Credentials¶
curl -H "X-AWS-Access-Key-Id: AKIA..." \
-H "X-AWS-Secret-Access-Key: ..." \
-H "X-AWS-Session-Token: ..." \
-H "X-AWS-Region: us-east-1" \
http://localhost:8000/api/v1/memory/ns
Service Credentials¶
Generic key-value credentials for any service:
curl -H "X-Cred-Langfuse-Public-Key: pk-..." \
-H "X-Cred-Langfuse-Secret-Key: sk-..." \
http://localhost:8000/api/v1/observability/traces
Server Credential Fallback¶
allow_server_credentials controls how the gateway resolves credentials when clients don't provide them via headers:
| Mode | Behavior |
|---|---|
never (default) |
Require per-user or header-provided credentials. Fail if missing. |
fallback |
Try per-user OIDC credentials first, then fall back to server ambient. |
always |
Always use server credentials (dev mode). |
Per-User Credential Resolution (OIDC)¶
In multi-tenant deployments, different users need different backend credentials. The credentials subsystem resolves per-user credentials from OIDC user attributes and populates the same contextvars that X-Cred-* headers populate. Providers work unchanged.
Convention-based naming: Use apg.{service}.{key} format (e.g., apg.langfuse.public_key). The resolver auto-discovers all apg.* attributes and maps them to service_credentials[service][key].
allow_server_credentials: fallback
credentials:
resolver: oidc # "noop" (default) or "oidc"
oidc:
aws:
enabled: false # Phase 4: STS AssumeRoleWithWebIdentity
writer:
backend: keycloak # "noop" (default) or "keycloak"
config:
admin_client_id: "${KC_ADMIN_CLIENT_ID}"
admin_client_secret: "${KC_ADMIN_CLIENT_SECRET}"
cache:
ttl_seconds: 300
max_entries: 10000
Keycloak setup:
- Create a confidential client with Service Accounts Roles enabled
- Assign
realm-managementroles:manage-users+manage-realm - Set credentials via the gateway UI Settings page (
/ui/settings)
The resolver reads user attributes directly from the Keycloak Admin API (when admin credentials are configured), bypassing the need for protocol mappers. Falls back to the userinfo endpoint when admin credentials are unavailable.
Credential resolution order:
- Explicit headers (
X-AWS-*,X-Cred-*) always win - OIDC-resolved credentials: per-user attributes from the identity provider
- Server ambient credentials: from environment (when mode is
fallbackoralways)
Authentication¶
The gateway supports pluggable authentication backends configured via the auth block.
Backends¶
# Noop (default) — dev mode, full access
auth:
backend: noop
# API key — static keys mapped to principals
auth:
backend: api_key
api_keys:
- key: "sk-dev-12345"
principal_id: "dev-user"
principal_type: "user"
groups: ["engineering"]
scopes: ["admin"]
# JWT — OIDC token validation
auth:
backend: jwt
jwt:
issuer: "https://keycloak.example.com/realms/my-realm"
audience: ""
client_id: "my-app-ui"
algorithms: ["RS256"]
claims_mapping:
groups: "groups"
scopes: "scope"
Resource Ownership¶
All agents, teams, and related resources track ownership for access control:
owner_idis set automatically from the authenticated principal on create.shared_with: []means private; only the owner can access. This is the default for API-created resources.shared_with: ["*"]means all authenticated users can view/use the resource. This is the default for config-seeded resources.- The owner can edit and delete the resource. Users in shared groups can view and use it. Users with the admin scope bypass all access checks.
Store Backend Configuration¶
Agent specs, team specs, and associated components (background run managers, session registries) are managed by pluggable store backends.
Store Configuration¶
Each subsystem (agents, teams) has a store block with backend and config:
agents:
store:
backend: file # "file", "redis", or dotted class path
config:
path: "agents.json" # Backend-specific kwargs
Available Backends¶
| Alias | Class | Config keys | Description |
|---|---|---|---|
file |
FileAgentStore / FileTeamStore |
path |
JSON file persistence (default, single-replica) |
redis |
RedisAgentStore / RedisTeamStore |
redis_url |
Redis hash storage (multi-replica) |
Custom backends can be specified by dotted class path instead of an alias.
Redis Backend¶
When using redis, the store also creates a RedisEventStore (for background run event persistence) and a RedisSessionRegistry (for cross-replica browser/code_interpreter session tracking). No additional config needed; these are wired up automatically.
agents:
store:
backend: redis
config:
redis_url: "redis://my-redis:6379/0"
teams:
store:
backend: redis
config:
redis_url: "redis://my-redis:6379/0"
providers:
tasks:
default: redis
backends:
redis:
backend: "agentic_primitives_gateway.primitives.tasks.redis.RedisTasksProvider"
config:
redis_url: "redis://my-redis:6379/0"
Tasks Provider¶
The tasks provider (for team task boards) is configured separately as a standard provider:
| Backend | Description |
|---|---|
NoopTasksProvider |
Returns empty results (default) |
InMemoryTasksProvider |
In-process task board with asyncio.Lock (dev) |
RedisTasksProvider |
Redis-backed with atomic Lua scripts (multi-replica) |
Checkpoint Configuration¶
Checkpointing makes agent and team runs durable across server restarts. When enabled, run state is saved to Redis before each LLM call, allowing another replica to resume on crash.
The same configuration applies to teams:
Checkpointing requires a Redis store backend (store.backend: redis) and a RedisEventStore for event persistence. When the store backend is already redis, the checkpoint store reuses the same connection.
Agent Configuration¶
agents:
store:
backend: file
config:
path: "agents.json"
specs:
research-assistant:
model: "us.anthropic.claude-sonnet-4-20250514-v1:0"
description: "A research assistant with long-term memory"
system_prompt: |
You are a research assistant with long-term memory.
primitives:
memory:
enabled: true
namespace: "agent:{agent_name}"
browser:
enabled: true
provider_overrides:
browser: "selenium_grid"
hooks:
auto_memory: true
auto_trace: false
max_turns: 20
temperature: 1.0
Agents defined in config are seeded into the store on startup. Config values overwrite existing agents with the same name.
Team Configuration¶
teams:
store:
backend: file
config:
path: "teams.json"
specs:
research-team:
description: "Researches and codes collaboratively"
planner: "planner"
synthesizer: "synthesizer"
workers: ["researcher", "coder"]
global_max_turns: 100
global_timeout_seconds: 300
See Teams for full documentation.
Policy Enforcement¶
enforcement:
backend: "agentic_primitives_gateway.enforcement.cedar.CedarPolicyEnforcer"
config:
policy_refresh_interval: 30
seed_policies:
- description: "Allow all"
policy_body: 'permit(principal, action, resource);'
Preset Configs¶
The four primary configs cover different deployment stages:
| Config | Command | What it does |
|---|---|---|
quickstart.yaml |
./run.sh |
Bedrock LLM + in-memory. No infra needed beyond AWS creds. |
agentcore.yaml |
./run.sh agentcore |
All AWS managed (AgentCore + Bedrock). Needs Redis. |
selfhosted.yaml |
./run.sh selfhosted |
Open-source backends (Milvus, Langfuse, Jupyter, Selenium). Needs Redis. |
mixed.yaml |
./run.sh mixed |
Both AgentCore + self-hosted backends + JWT + Cedar + credentials. |
Full Config Reference (mixed.yaml)¶
The mixed.yaml config demonstrates every configuration feature. Each section is annotated below.
Authentication¶
auth:
backend: jwt # "noop" (dev), "api_key", or "jwt"
jwt:
issuer: "${JWT_ISSUER}" # OIDC issuer URL (required)
audience: "${JWT_AUDIENCE:-}" # Expected audience (optional)
client_id: "${JWT_CLIENT_ID:=agentic-gateway}" # Public client for UI OIDC flow
algorithms: ["RS256"] # JWT signing algorithms
claims_mapping:
groups: "groups" # Claim name for group membership
scopes: "scope" # Claim name for scopes (admin check)
With jwt auth, all API requests (except /healthz, /auth/config, /ui/) require a valid JWT. The UI uses OIDC Authorization Code + PKCE flow to get tokens. is_admin checks for "admin" in either scopes or groups.
Cedar Policy Enforcement¶
enforcement:
backend: "agentic_primitives_gateway.enforcement.cedar.CedarPolicyEnforcer"
config:
policy_refresh_interval: 5 # Seconds between policy reloads
Default-deny when active. Policies are loaded from the policy primitive provider and evaluated on every request. Exempt paths: /healthz, /readyz, /ui/, /api/v1/policy, /auth/config.
Providers (Multi-Backend)¶
Each primitive has a default and a backends map. Both run simultaneously — switch per-request via X-Provider-* headers:
providers:
memory:
default: "mem0" # Used when no override is specified
backends:
mem0: # Self-hosted: mem0 + Milvus vector store
backend: "agentic_primitives_gateway.primitives.memory.mem0_provider.Mem0MemoryProvider"
config:
vector_store:
provider: milvus
config:
collection_name: agentic_memories
url: "http://localhost:19530"
embedding_model_dims: 1024
llm:
provider: aws_bedrock
config:
model: us.anthropic.claude-sonnet-4-20250514-v1:0
embedder:
provider: aws_bedrock
config:
model: amazon.titan-embed-text-v2:0
agentcore: # AWS managed: AgentCore memory
backend: "agentic_primitives_gateway.primitives.memory.agentcore.AgentCoreMemoryProvider"
config:
region: "us-east-1"
memory_id: "${AGENTCORE_MEMORY_ID}"
Override at request time: curl -H "X-Provider-Memory: agentcore" ...
The same multi-backend pattern applies to all primitives: observability (langfuse/agentcore), code_interpreter (jupyter/agentcore), browser (selenium_grid/agentcore), etc.
Credential Resolution¶
allow_server_credentials: fallback # "never", "fallback", or "always"
credentials:
resolver: oidc # "noop" or "oidc"
oidc:
aws:
enabled: false # Resolve AWS creds from OIDC attributes?
writer:
backend: keycloak # Write credentials back to Keycloak
config:
admin_client_id: "${KC_ADMIN_CLIENT_ID}" # Service account client
admin_client_secret: "${KC_ADMIN_CLIENT_SECRET}"
cache:
ttl_seconds: 300 # Cache resolved credentials for 5min
max_entries: 10000
Resolution order: explicit headers (X-Cred-*) → OIDC user attributes (apg.*) → server ambient credentials.
The oidc resolver reads apg.{service}.{key} attributes from the user's identity provider profile. For example, if user Alice has apg.langfuse.public_key in Keycloak, the Langfuse provider gets her key automatically. The Settings page in the UI writes credentials back via the keycloak writer.
Agent and Team Stores¶
agents:
store:
backend: redis # "file" or "redis"
config:
redis_url: "redis://localhost:6379/0"
teams:
store:
backend: redis
config:
redis_url: "redis://localhost:6379/0"
File stores persist to JSON (single-replica). Redis stores enable multi-replica deployments where any pod can serve any request.
Environment Variable Expansion¶
All config values support ${VAR}, ${VAR:=default} (set if unset), and ${VAR:-default} (use default but don't set) syntax. This makes configs portable across environments without editing YAML.
Hot Reload¶
The gateway watches the config file for changes (useful with Kubernetes ConfigMaps):