Skip to content

← Back to YouLab

The HTTP service is a FastAPI application that provides RESTful endpoints for agent management and chat functionality.

PropertyValue
Default Host127.0.0.1
Default Port8100
FrameworkFastAPI
Entry Pointsrc/youlab_server/server/main.py
Terminal window
# Using the CLI
uv run youlab-server
# With custom settings
YOULAB_SERVICE_HOST=0.0.0.0 \
YOULAB_SERVICE_PORT=8000 \
uv run youlab-server
GET /health

Returns service health status and Letta connection state.

Response:

{
"status": "ok",
"letta_connected": true,
"honcho_connected": true,
"version": "0.1.0"
}
StatusMeaning
okService healthy, Letta connected
degradedService running, Letta unavailable

Note: honcho_connected indicates whether Honcho message persistence is available. The service functions without Honcho (messages won’t be persisted for ToM analysis).


POST /agents

Creates a new agent for a user from a template.

Request Body:

{
"user_id": "user123",
"agent_type": "tutor",
"user_name": "Alice"
}
FieldTypeRequiredDefaultDescription
user_idstringYes-Unique user identifier
agent_typestringNo"tutor"Template to use
user_namestringNonullUser’s display name

Response (201 Created):

{
"agent_id": "agent-abc123",
"user_id": "user123",
"agent_type": "tutor",
"agent_name": "youlab_user123_tutor",
"created_at": "2025-12-31T10:00:00Z"
}

Errors:

  • 400 - Unknown agent type
  • 503 - Letta unavailable

GET /agents/{agent_id}

Retrieves agent information by ID.

Response:

{
"agent_id": "agent-abc123",
"user_id": "user123",
"agent_type": "tutor",
"agent_name": "youlab_user123_tutor",
"created_at": "2025-12-31T10:00:00Z"
}

Errors:

  • 404 - Agent not found

GET /agents
GET /agents?user_id=user123

Lists agents, optionally filtered by user.

Query Parameters:

ParameterTypeDescription
user_idstringFilter by user ID

Response:

{
"agents": [
{
"agent_id": "agent-abc123",
"user_id": "user123",
"agent_type": "tutor",
"agent_name": "youlab_user123_tutor",
"created_at": "2025-12-31T10:00:00Z"
}
]
}

POST /chat

Sends a message and waits for complete response.

Request Body:

{
"agent_id": "agent-abc123",
"message": "Help me brainstorm essay topics",
"chat_id": "chat-xyz",
"chat_title": "Essay Brainstorming"
}
FieldTypeRequiredDescription
agent_idstringYesTarget agent
messagestringYesUser’s message
chat_idstringNoOpenWebUI chat ID
chat_titlestringNoCurrent chat title

Response:

{
"response": "Great! Let's explore some essay topics...",
"agent_id": "agent-abc123"
}

Errors:

  • 404 - Agent not found
  • 503 - Failed to communicate with agent

POST /chat/stream

Sends a message with Server-Sent Events (SSE) response.

Request Body:

{
"agent_id": "agent-abc123",
"message": "What makes a compelling personal narrative?",
"chat_id": "chat-xyz",
"chat_title": "Essay Writing",
"enable_thinking": true
}
FieldTypeRequiredDefaultDescription
agent_idstringYes-Target agent
messagestringYes-User’s message
chat_idstringNonullChat ID
chat_titlestringNonullChat title
enable_thinkingboolNotrueShow thinking indicators

Response (SSE stream):

data: {"type": "status", "content": "Thinking..."}
data: {"type": "status", "content": "Using memory_search..."}
data: {"type": "message", "content": "A compelling personal narrative has..."}
data: {"type": "done"}

Event Types:

TypeDescription
statusProcessing indicator (thinking, tool use)
messageActual response content
doneStream complete
errorError occurred

The strategy agent provides RAG capabilities for project knowledge.

POST /strategy/documents

Uploads content to the strategy agent’s archival memory.

Request Body:

{
"content": "# Architecture\n\nYouLab uses a layered architecture...",
"tags": ["architecture", "design"]
}

Response (201 Created):

{
"success": true
}

POST /strategy/ask

Queries the strategy agent (searches archival memory first).

Request Body:

{
"question": "What is the YouLab architecture?"
}

Response:

{
"response": "Based on the documentation, YouLab uses..."
}

GET /strategy/documents?query=architecture&limit=5

Searches archival memory directly.

Query Parameters:

ParameterTypeDefaultDescription
querystringRequiredSearch query
limitint5Max results

Response:

{
"documents": [
"[TAGS: architecture, design]\n# Architecture\n...",
"[TAGS: overview]\n# System Overview\n..."
]
}

GET /strategy/health

Checks strategy agent status.

Response:

{
"status": "ready",
"agent_exists": true
}

Background agents run scheduled or manual tasks to enrich agent memory using Honcho dialectic queries. See Background Agents for full documentation.

Location: src/youlab_server/server/background.py

GET /background/agents

Lists all configured background agents across all courses.

Response:

[
{
"id": "insight-harvester",
"name": "Student Insight Harvester",
"course_id": "college-essay",
"enabled": true,
"triggers": {
"schedule": "0 3 * * *",
"idle_enabled": false,
"manual": true
},
"query_count": 3
}
]

POST /background/{agent_id}/run

Manually triggers a background agent run.

Path Parameters:

ParameterDescription
agent_idBackground agent ID (e.g., insight-harvester)

Request Body (optional):

{
"user_ids": ["user123", "user456"]
}
FieldTypeRequiredDescription
user_idsarrayNoSpecific users to process (null = all)

Response:

{
"agent_id": "insight-harvester",
"started_at": "2025-01-08T03:00:00Z",
"completed_at": "2025-01-08T03:05:00Z",
"users_processed": 25,
"queries_executed": 75,
"enrichments_applied": 68,
"error_count": 7,
"errors": ["Enrichment failed for user789/learning_style: ..."]
}

Errors:

  • 404 - Background agent not found
  • 500 - Background system not initialized

POST /background/config/reload

Hot-reloads TOML configuration files from disk.

Query Parameters:

ParameterTypeDefaultDescription
config_dirstringconfig/coursesDirectory to load from

Response:

{
"success": true,
"courses_loaded": 1,
"course_ids": ["college-essay"],
"message": "Configuration reloaded successfully"
}

The curriculum system provides course configuration management.

Location: src/youlab_server/server/curriculum.py

GET /curriculum/courses

Lists all available courses.

Response:

{
"courses": ["default", "college-essay"],
"count": 2
}

GET /curriculum/courses/{course_id}

Returns course metadata and structure.

Response:

{
"id": "college-essay",
"name": "College Essay Coaching",
"version": "1.0.0",
"description": "AI-powered tutoring for college application essays",
"modules": [
{"id": "01-self-discovery", "name": "Self-Discovery", "step_count": 3}
],
"blocks": [
{"name": "persona", "label": "persona", "field_count": 7}
],
"background_agents": ["insight-harvester"],
"tool_count": 3
}

GET /curriculum/courses/{course_id}/full

Returns complete course configuration as JSON (useful for debugging or UI editors).

Response: Full CourseConfig serialized to JSON.


GET /curriculum/courses/{course_id}/modules

Returns all modules with full step details.

Response: List of ModuleConfig serialized to JSON.


POST /curriculum/reload

Hot-reloads all curriculum configurations from disk.

Response:

{
"success": true,
"courses_loaded": 2,
"courses": ["default", "college-essay"],
"message": "Configuration reloaded successfully"
}

The AgentManager class handles all agent operations.

agent_name = f"youlab_{user_id}_{agent_type}"
# Example: youlab_user123_tutor
metadata = {
"youlab_user_id": user_id,
"youlab_agent_type": agent_type,
}
# Cache structure
_cache: dict[tuple[str, str], str] # (user_id, agent_type) -> agent_id
# Lookup order
1. Check cache
2. Query Letta by agent name
3. Return None if not found

On service startup, the cache is rebuilt from Letta:

async def lifespan(app):
count = await app.state.agent_manager.rebuild_cache()
log.info("startup_complete", cached_agents=count)

Agents can be created from TOML course configurations:

agent_id = manager.create_agent_from_curriculum(
user_id="user123",
course_id="college-essay",
user_name="Alice",
block_overrides={"human": {"name": "Alice"}},
)

This method:

  • Loads configuration from config/courses/{course_id}/course.toml
  • Builds memory blocks from TOML schema definitions
  • Configures tools and tool rules from course config
  • Uses course-specified model and embedding
  • Adds course metadata to agent

The service translates Letta streaming chunks to SSE events:

Letta TypeSSE Event
reasoning_message{"type": "status", "content": "Thinking..."}
tool_call_message{"type": "status", "content": "Using {tool}..."}
assistant_message{"type": "message", "content": "..."}
stop_reason{"type": "done"}
ping": keepalive\n\n"
error_message{"type": "error", "message": "..."}

Letta appends JSON metadata to messages. The service strips it:

# Before: "Here are some topics...{"follow_ups": ["What about..."]}"
# After: "Here are some topics..."

All chat requests are traced via Langfuse:

with trace_chat(
user_id=user_id,
agent_id=request.agent_id,
chat_id=request.chat_id,
metadata={"chat_title": request.chat_title},
) as trace_ctx:
response_text = manager.send_message(...)
trace_generation(trace_ctx, ...)

See Configuration for Langfuse settings.


StatusCondition
400Invalid request (unknown agent type)
404Agent not found
500Internal error
503Letta unavailable

All errors include a detail field:

{
"detail": "Agent not found: agent-abc123"
}