🔌 Traylinx Cortex Integration Guide¶
📚 Navigation: Main README | Docs Index | API Reference | Database Schema
This document outlines how Traylinx Cortex integrates with the wider Traylinx ecosystem, including authentication via Sentinel, discovery via Agent Registry, and communication via A2A protocols.
1. 🔐 Authentication (Traylinx Sentinel)¶
Cortex acts as both a Consumer (calling LLMs/SwitchAI) and a Provider (serving chat APIs to other agents/apps). It must be fully secured using Traylinx Sentinel.
A. Identity Setup¶
Cortex requires its own credentials in Sentinel:
* Client ID: traylinx-cortex
* Client Secret: (Managed via Environment Variable)
* Agent User ID: (Unique UUID for Cortex)
B. Authentication Headers¶
All A2A requests to Cortex must include these headers:
Content-Type: application/vnd.traylinx.a2a+json; version=1
Authorization: Bearer {access_token}
X-Agent-Key: {agent_key}
X-Agent-Secret-Token: {agent_secret}
| Header | Description |
|---|---|
Content-Type |
A2A protocol content type with version |
Authorization |
Bearer token from Sentinel (OAuth2) |
X-Agent-Key |
Your agent's unique identifier |
X-Agent-Secret-Token |
Your agent's secret for additional verification |
C. Protecting Endpoints (Provider Mode)¶
All Cortex A2A endpoints must be protected using the traylinx_auth_client SDK.
Python Example:
from traylinx_auth_client import require_a2a_auth
from fastapi import APIRouter, Request
router = APIRouter()
@router.post("/a2a/conversation/chat")
@require_a2a_auth # <--- Enforces Sentinel Authentication
async def chat_endpoint(request: Request, payload: A2AChatRequest):
# If we reach here, the request is authenticated
# The calling agent's identity is available in request.state.agent
agent_key = request.state.agent["agent_key"]
return await cortex_manager.process(payload)
D. Making Requests (Consumer Mode)¶
When Cortex needs to call other internal agents (e.g., if it needs to delegate a task), it uses the SDK to sign requests.
Python Example:
from traylinx_auth_client import make_a2a_request
# Example: Cortex calling a specialized "Math Agent"
response = make_a2a_request(
method="POST",
url="http://math-agent:8080/a2a/calculate",
json={
"envelope": {
"message_id": str(uuid.uuid4()),
"sender_agent_key": "traylinx-cortex",
"timestamp": datetime.utcnow().isoformat() + "Z"
},
"action": "calculate",
"payload": {"expression": "2 + 2"}
}
)
2. 📡 A2A Protocol Format¶
Request Envelope Structure¶
All A2A requests follow this standard envelope format:
{
"envelope": {
"message_id": "msg-uuid-001",
"sender_agent_key": "calling-agent",
"timestamp": "2025-11-27T10:00:00Z",
"correlation_id": "optional-for-threading"
},
"action": "conversation.chat",
"payload": {
// Action-specific data
}
}
Response Envelope Structure¶
{
"envelope": {
"message_id": "response-uuid-001",
"correlation_id": "msg-uuid-001",
"in_reply_to": "msg-uuid-001",
"sender_agent_key": "traylinx-cortex",
"timestamp": "2025-11-27T10:00:01Z"
},
"action": "conversation.chat",
"payload": {
// Response data
}
}
Cortex A2A Actions¶
| Action | Endpoint | Description |
|---|---|---|
conversation.chat |
POST /a2a/conversation/chat |
Send message and get AI response |
conversation.create |
POST /a2a/conversation/create |
Create new conversation session |
conversation.history |
POST /a2a/conversation/history |
Get conversation history |
3. 📬 A2A Endpoint Examples¶
3.1. Create Conversation (A2A)¶
Endpoint: POST /a2a/conversation/create
Request:
{
"envelope": {
"message_id": "msg-001",
"sender_agent_key": "my-agent",
"timestamp": "2025-11-27T10:00:00Z"
},
"action": "conversation.create",
"payload": {
"user_id": "user-123",
"app_id": "my-app",
"metadata": {
"language": "en",
"source": "agent"
}
}
}
Response (201 Created):
{
"envelope": {
"message_id": "response-001",
"correlation_id": "msg-001",
"in_reply_to": "msg-001",
"sender_agent_key": "traylinx-cortex",
"timestamp": "2025-11-27T10:00:01Z"
},
"action": "conversation.create",
"payload": {
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"created_at": "2025-11-27T10:00:01Z"
}
}
3.2. Chat (A2A)¶
Endpoint: POST /a2a/conversation/chat
Request:
{
"envelope": {
"message_id": "msg-002",
"sender_agent_key": "my-agent",
"timestamp": "2025-11-27T10:00:05Z"
},
"action": "conversation.chat",
"payload": {
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"message": "I'm planning a trip to Tokyo. Can you help?",
"user_id": "user-123",
"config": {
"stream": false,
"model_preference": "balanced",
"switch_ai_api_key": "sk-user-specific-key",
"embedding_model": "mistral-embed"
}
}
}
Response (200 OK):
{
"envelope": {
"message_id": "response-002",
"correlation_id": "msg-002",
"in_reply_to": "msg-002",
"sender_agent_key": "traylinx-cortex",
"timestamp": "2025-11-27T10:00:07Z"
},
"action": "conversation.chat",
"payload": {
"message_id": "msg_abc123",
"content": "Sure! Tokyo is amazing. What aspects of your trip would you like help with?",
"usage": {
"tokens_in": 50,
"tokens_out": 25
},
"cost_usd": 0.000150
}
}
4. 📢 Agent Registry (Discovery)¶
To make Cortex discoverable by other agents (e.g., the Router or Orchestrator), it must register itself with the Traylinx Agent Registry.
Registration Payload¶
On startup, Cortex should send a heartbeat/registration request to the Registry.
Endpoint: POST /a2a/registry/register
Payload:
{
"envelope": {
"message_id": "reg-001",
"sender_agent_key": "traylinx-cortex",
"timestamp": "2025-11-27T10:00:00Z"
},
"action": "registry.register",
"payload": {
"agent_key": "traylinx-cortex",
"name": "Traylinx Cortex",
"description": "The cognitive core providing unified memory and conversation management.",
"endpoint_url": "http://traylinx-cortex:8000",
"capabilities": [
{
"key": "domain",
"value": "conversation",
"description": "Handles general conversational flows"
},
{
"key": "feature",
"value": "memory",
"description": "Provides short-term and long-term memory storage"
},
{
"key": "feature",
"value": "llm-proxy",
"description": "Proxies requests to LLMs with context injection"
}
],
"version": "2.0.0"
}
}
Discovery by Others¶
Other agents can find Cortex by querying the Registry for the conversation domain.
Query:
{
"envelope": {...},
"action": "registry.query",
"payload": {
"capabilities": [
{"key": "domain", "value": "conversation"}
]
}
}
5. 🔄 A2A Communication Flow¶
Here is how a typical interaction flows through the system:
6. 🏥 Health Endpoints¶
Cortex exposes health endpoints for orchestration systems:
| Endpoint | Purpose | Response |
|---|---|---|
GET /health |
Liveness probe | {"status": "ok"} |
GET /health/live |
Detailed health | {"status": "healthy", "checks": {...}} |
GET /ready |
Readiness probe (K8s) | {"status": "ready"} or 503 |
Readiness Check Logic:
@router.get("/ready")
async def readiness():
postgres_ok = await check_postgres()
redis_ok = await check_redis()
if postgres_ok and redis_ok:
return {"status": "ready"}
else:
raise HTTPException(status_code=503, detail="Not ready")
7. 🛠️ Implementation Checklist¶
Authentication & Security¶
- [ ] Install SDK: Add
traylinx-auth-clienttopyproject.toml - [ ] Env Variables: Configure
SENTINEL_URL,REGISTRY_URL,CLIENT_ID,CLIENT_SECRET,AGENT_USER_ID - [ ] Middleware: Add A2A Auth middleware to FastAPI app
- [ ] Verify Headers: Ensure Content-Type and auth headers are validated
Service Discovery¶
- [ ] Lifecycle Hook: Add
on_startuphandler to register with Agent Registry - [ ] Heartbeat: Setup background task to send heartbeats to Registry every 30s
- [ ] Graceful Shutdown: Deregister from Registry on shutdown
A2A Protocol¶
- [ ] Envelope Parsing: Implement A2A envelope validation
- [ ] Correlation IDs: Propagate
message_idtocorrelation_idin responses - [ ] Error Format: Return errors in A2A envelope format
8. 🐛 Troubleshooting¶
A2A Authentication Failures¶
Symptoms: 401 Unauthorized responses
Check:
1. Valid access_token from Sentinel (not expired)
2. Valid agent_secret_token for your agent
3. Matching X-Agent-Key header with token's agent
4. Correct Content-Type header
# Test token validity
curl -X POST ${SENTINEL_URL}/introspect \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-d "token=${ACCESS_TOKEN}"
Connection Issues¶
# Test Cortex health
curl http://localhost:8000/health
# Test readiness
curl http://localhost:8000/ready
# Check detailed health
curl http://localhost:8000/health/live
Invalid A2A Format¶
Symptoms: 400 Bad Request with validation errors
Check:
1. envelope object present with required fields
2. action field matches endpoint
3. payload contains required data
4. Timestamps in ISO 8601 format
9. 🚦 Production Checklist¶
Before deploying Cortex to production:
Infrastructure¶
- [ ] Configure production
DATABASE_URLandREDIS_URL - [ ] Set up database backups and replication
- [ ] Configure container orchestration (K8s)
- [ ] Set up load balancer with health checks
Security¶
- [ ] Production Sentinel credentials configured
- [ ] TLS/HTTPS enabled on all endpoints
- [ ] API keys rotated from development values
- [ ] PII scrubbing tested with real data patterns
Observability¶
- [ ] Log aggregation configured (ELK, Datadog, etc.)
- [ ] LangSmith/OpenTelemetry tracing enabled
- [ ] Monitoring alerts for error rates, latency
- [ ] Cost tracking dashboards configured
Performance¶
- [ ] Load test with expected concurrent users
- [ ] Vector index performance validated
- [ ] Redis connection pooling configured
- [ ] Celery worker scaling tested
Reliability¶
- [ ] LLM fallback chain tested
- [ ] Circuit breaker thresholds tuned
- [ ] Rate limiting configured in Sentinel
- [ ] Graceful degradation tested
10. 📚 Related Documentation¶
| Document | Purpose |
|---|---|
specs_v2_final.md |
Complete API specification |
implementation_plan_v2_final.md |
Step-by-step development guide |
./QUICK_REFERENCE.md |
One-page developer cheat sheet |
gcam_research.md |
Architectural background |
Built with: FastAPI, LangGraph, LiteLLM, PostgreSQL + pgvector, Redis, Celery