os.agno.com not persisting user sessions with localhost AgentOS - POST requests missing cookies

I’m experiencing an issue where os.agno.com connects successfully to my localhost AgentOS instance but doesn’t maintain user sessions across chat messages. Each POST request creates a new session instead of reusing the existing one.

Setup:

  • AgentOS running on http://localhost:7777
  • Connecting from os.agno.com to localhost
  • Using standard AgentOS implementation with user session middleware
  • CORS properly configured with https://os.agno.com in allowed origins

What’s Working:
:white_check_mark: os.agno.com connects successfully (green light, “connected” status)
:white_check_mark: Can see agents and send/receive messages
:white_check_mark: GET requests work properly and reuse sessions
:white_check_mark: Direct browser access to localhost:7777 maintains sessions perfectly

The Problem:
:cross_mark: Every chat message (POST to /agents/{agent}/runs) creates a new user session
:cross_mark: No conversation memory between messages
:cross_mark: POST requests from os.agno.com contain no cookies (Cookie header missing)

Technical Details:

Request Headers (POST from os.agno.com):

  • Origin: https://os.agno.com :white_check_mark:
  • Cookie: [missing] :cross_mark:

Response Headers (from localhost):

  • Set-Cookie: user_id=...; Max-Age=2592000; Path=/; SameSite=Lax :white_check_mark:
  • Access-Control-Allow-Credentials: true :white_check_mark:
  • Access-Control-Allow-Origin: https://os.agno.com :white_check_mark:

Browser Cookies:

  • Cookies for agno.com domain: Present :white_check_mark:
  • Cookies for localhost:7777 domain: Missing :cross_mark:

The Issue:
The browser is not storing cookies set by the localhost server when requests come from os.agno.com. This appears to be related to cross-origin cookie handling between HTTPS (os.agno.com) and HTTP (localhost:7777).

Question:
Is there a specific configuration or cookie setting required for os.agno.com to properly handle user sessions with localhost AgentOS instances? Other users seem to use this setup successfully, so I’m wondering if there’s something I’m missing.

Environment:

  • Browser: [Your browser]
  • OS: Ubuntu
  • AgentOS: Latest version
  • Python: 3.12

Code:

#!/usr/bin/env python3
"""
AgentOS Server - Optimized Performance with Cirkelline Personal Assistant
"""

import os
import uuid
import time
from typing import Dict, Any
from agno.agent import Agent
from agno.db.postgres import PostgresDb
from agno.models.google import Gemini
from agno.os import AgentOS
from agno.tools.duckduckgo import DuckDuckGoTools
from agno.tools.exa import ExaTools
from agno.tools.tavily import TavilyTools
from agno.tools.googlesearch import GoogleSearchTools
from agno.tools.reasoning import ReasoningTools
from fastapi import Request, Response
from fastapi.middleware.cors import CORSMiddleware
from utils.api_key_manager import api_key_manager

# Database configuration
start_time_db = time.time()
DATABASE_URL = os.getenv(
    "DATABASE_URL",
    "postgresql+psycopg://postgres:VEMKc9HJU1px87i7AtBt@cirkelline-db.crm4mi2uozbi.eu-north-1.rds.amazonaws.com:5432/cirkelline-db"
)
db = PostgresDb(db_url=DATABASE_URL)
print(f"Startup: Database connection initialized in {time.time() - start_time_db:.2f} seconds")

# Search tools initialization
start_time_tools = time.time()
search_tools = [
    ReasoningTools(),
    DuckDuckGoTools(timeout=90, fixed_max_results=2),
    ExaTools(),
    TavilyTools(),
    GoogleSearchTools(),
]
print(f"Startup: Search tools initialized in {time.time() - start_time_tools:.2f} seconds")

# Create a single default agent for AgentOS initialization
def create_default_agent() -> Agent:
    return Agent(
        name="Cirkelline",
        model=Gemini(
            id="gemini-2.5-flash",
            api_key=api_key_manager.get_key_for_component("main_agent")
        ),
        db=db,
        user_id="default",
        tools=search_tools,
        description="""You are Cirkelline, a warm and thoughtful personal assistant created by kv1nt. 
        You're like a close friend who genuinely cares about the person you're helping - someone who 
        remembers the little details, asks about their day, and provides support with a personal touch.""",
        
        instructions=[
            "Be conversational and friendly - like talking to a good friend over coffee",
            "Remember and reference previous conversations naturally - 'How did that meeting go?' or 'Still working on that project?'",
            "Ask thoughtful follow-up questions about their day, mood, or ongoing situations",
            "Show genuine interest in their life - celebrate wins, offer support during challenges",
            "Use their name when you know it, and remember personal details they share",
            "Be proactive - suggest things, offer reminders, or check in on past topics",
            "Keep responses warm but concise - like a friend who listens well and speaks thoughtfully",
            "When appropriate, share observations or gentle advice based on what you know about them"
        ],
        
        # Enable memory features
        enable_user_memories=True,
        enable_session_summaries=True,
        add_history_to_context=True,
        add_datetime_to_context=True,
        markdown=True,
        exponential_backoff=True,
        delay_between_retries=2,
        retries=5,
    )

# Cache for user agents to avoid recreation
user_agents_cache: Dict[str, Dict[str, Agent]] = {}

def get_user_agents(user_id: str) -> Dict[str, Agent]:
    """Get or create agents for a specific user (with caching)"""
    if user_id not in user_agents_cache:
        start_time_create_agents_total = time.time()

        start_time_cirkelline_agent = time.time()
        cirkelline_agent_instance = Agent(
            name="Cirkelline",
            model=Gemini(
                id="gemini-2.5-flash",
                api_key=api_key_manager.get_key_for_component("main_agent")
            ),
            db=db,
            user_id=user_id,
            tools=search_tools,
            description="""You are Cirkelline, a warm and thoughtful personal assistant created by kv1nt.
            You're like a close friend who genuinely cares about the person you're helping - someone who
            remembers the little details, asks about their day, and provides support with a personal touch.""",
            
            instructions=[
                "Be conversational and friendly - like talking to a good friend over coffee",
                "Remember and reference previous conversations naturally - 'How did that meeting go?' or 'Still working on that project?'",
                "Ask thoughtful follow-up questions about their day, mood, or ongoing situations",
                "Show genuine interest in their life - celebrate wins, offer support during challenges",
                "Use their name when you know it, and remember personal details they share",
                "Be proactive - suggest things, offer reminders, or check in on past topics",
                "Keep responses warm but concise - like a friend who listens well and speaks thoughtfully",
                "When appropriate, share observations or gentle advice based on what you know about them"
            ],
            
            # Enable memory features
            enable_user_memories=True,
            enable_session_summaries=True,
            add_history_to_context=True,
            add_datetime_to_context=True,
            markdown=True,
            exponential_backoff=True,
            delay_between_retries=2,
            retries=5,
        )
        print(f"Request: Cirkelline agent for user {user_id[:8]}... created in {time.time() - start_time_cirkelline_agent:.2f} seconds")

        start_time_research_agent = time.time()
        research_specialist_instance = Agent(
            name="Research Specialist",
            model=Gemini(
                id="gemini-1.5-pro",
                api_key=api_key_manager.get_key_for_component("research_team_1")
            ),
            db=db,
            user_id=user_id,
            tools=search_tools,
            enable_user_memories=True,
            role="Expert at finding and analyzing information with a friendly, helpful approach",
            markdown=True,
            add_datetime_to_context=True,
            exponential_backoff=True,
            delay_between_retries=2,
            retries=5,
        )
        print(f"Request: Research specialist agent for user {user_id[:8]}... created in {time.time() - start_time_research_agent:.2f} seconds")

        user_agents_cache[user_id] = {
            "cirkelline_personal_assistant": cirkelline_agent_instance,
            "research_specialist": research_specialist_instance
        }
        print(f"Request: Total agents for user {user_id[:8]}... created in {time.time() - start_time_create_agents_total:.2f} seconds")
    
    return user_agents_cache[user_id]

# Initialize AgentOS with default agent
start_time_agentos_init = time.time()
agent_os = AgentOS(
    os_id="cirkelline-os",
    description="Cirkelline - Your personal assistant",
    agents=[create_default_agent()],
)
app = agent_os.get_app()
print(f"Startup: AgentOS app initialized in {time.time() - start_time_agentos_init:.2f} seconds")

# CORS configuration
CORS_ALLOW_ORIGINS_LIST = os.getenv("CORS_ALLOW_ORIGINS_LIST")

if CORS_ALLOW_ORIGINS_LIST:
    allowed_origins = [origin.strip() for origin in CORS_ALLOW_ORIGINS_LIST.split(',')]
else:
    allowed_origins = [
        "https://cirkelline-chat.vercel.app",
        "https://chat.cirkelline.com",
        "http://localhost:3000",
        "https://os.agno.com",
    ]

app.add_middleware(
    CORSMiddleware,
    allow_origins=allowed_origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# User session middleware for proper user isolation
@app.middleware("http")
async def user_session_middleware(request: Request, call_next):
    start_time_middleware = time.time()
    
    # Skip user session logic for OPTIONS requests (CORS preflight)
    if request.method == "OPTIONS":
        response = await call_next(request)
        return response
    
    # Get or create user_id
    user_id = request.cookies.get("user_id")
    if not user_id:
        user_id = str(uuid.uuid4())
        print(f"🌐 New Cirkelline session: {user_id[:8]}...")
    else:
        print(f"🔄 Existing Cirkelline session: {user_id[:8]}...")
    
    # Store user_id in request state
    request.state.user_id = user_id
    request.state.user_agents = get_user_agents(user_id)
    
    response = await call_next(request)
    
    # Set cookie if new user
    if not request.cookies.get("user_id"):
        if request.url.hostname == "localhost" or request.url.hostname == "127.0.0.1":
            # Localhost development settings
            response.set_cookie(
                key="user_id",
                value=user_id,
                httponly=False,
                samesite="Lax",
                secure=False,
                max_age=30*24*60*60,  # 30 days
                path="/"
            )
        else:
            # Production settings
            response.set_cookie(
                key="user_id",
                value=user_id,
                httponly=True,
                samesite="Lax",
                secure=True,
                max_age=30*24*60*60,  # 30 days
                path="/"
            )
    
    print(f"Request: Processed for user {user_id[:8]}... in {time.time() - start_time_middleware:.2f} seconds")
    return response

# Health endpoint
@app.get("/health")
async def health_check():
    start_time_health = time.time()
    response = {"status": "healthy", "timestamp": time.time()}
    print(f"Request: Health check responded in {time.time() - start_time_health:.2f} seconds")
    return response

# Override agent selection to use user-specific agents
@app.middleware("http")
async def agent_override_middleware(request: Request, call_next):
    """Override the default agent with user-specific agents"""
    if hasattr(request.state, 'user_agents') and request.url.path.startswith('/v1/'):
        # Replace the default agents with user-specific ones
        agent_os.agents = list(request.state.user_agents.values())
        # CRITICAL: Set the user_id for all agents to match the session user_id
        for agent in agent_os.agents:
            agent.user_id = request.state.user_id
    
    response = await call_next(request)
    return response

if __name__ == "__main__":
    import uvicorn
    
    print("🌐 CIRKELLINE - Your Personal Assistant")
    print(f"🔑 API Keys: {api_key_manager.get_key_count()} (Capacity: {api_key_manager.get_total_capacity()} req/min)")
    print("✨ Personal memories and thoughtful conversations")
    print("💝 Created by kv1nt with care")
    print("📍 Frontend: http://localhost:3000")
    
    uvicorn.run("agentos_server:app", host="0.0.0.0", port=7777)

Any guidance would be greatly appreciated!

Hey @eenvy, thanks for reaching out and supporting Agno. I’ve shared this with the team, we’re working through all requests one by one and will get back to you soon.If it’s urgent, please let us know. We appreciate your patience!

1 Like

Hi @eenvy , AgentOS endpoints themselves don’t require cookie-based auth , cookies are only used during authentication flows handled by the https://os-api.agno.com api calls . Once authenticated, the AgentOS calls (like sending/receiving messages) don’t rely on cookies for session handling. Thanks