Implement single-endpoint chat API with deterministic request orchestration. This skill should be used when users need to create /api/{user_id}/chat endpoint, implement request validation, resolve conversation IDs, call agent runners, or design chat API contracts with structured responses.
Scanned 2/12/2026
Install to Claude Code
npx -y skills add majiayu000/claude-skill-registry --skill chat-api-orchestration --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Chat Api Orchestration?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/majiayu000-chat-api-orchestration)More formats (shields.io, HTML) on the badges page.
---
name: chat-api-orchestration
description: |
Implement single-endpoint chat API with deterministic request orchestration.
This skill should be used when users need to create /api/{user_id}/chat endpoint,
implement request validation, resolve conversation IDs, call agent runners,
or design chat API contracts with structured responses.
---
# Chat API Orchestration
Guide for implementing a single-endpoint chat API with deterministic request flow.
## What This Skill Does
- Design `/api/{user_id}/chat` endpoint contract
- Implement deterministic 5-step request flow
- Validate incoming chat requests
- Resolve or create conversation_id
- Orchestrate agent runner calls
- Return structured responses
## What This Skill Does NOT Do
- Implement the agent/LLM logic itself
- Handle conversation persistence (see conversation-state-management skill)
- Manage authentication tokens (assumes auth exists)
- Deploy or scale the API
---
## Before Implementation
Gather context to ensure successful implementation:
| Source | Gather |
|--------|--------|
| **Codebase** | Existing routers, auth dependencies, error handling patterns |
| **Conversation** | User's agent runner interface, specific response fields needed |
| **Skill References** | API contract, request flow, error handling patterns |
| **User Guidelines** | Project conventions, existing schema patterns |
---
## Core Architecture
### Single Endpoint Design
```
POST /api/{user_id}/chat
│
▼
┌─────────────────────────────────────────┐
│ DETERMINISTIC FLOW │
│ │
│ 1. Validate Request │
│ 2. Authenticate User │
│ 3. Resolve Conversation │
│ 4. Execute Agent │
│ 5. Return Response │
│ │
└─────────────────────────────────────────┘
```
### Why Single Endpoint?
| Benefit | Description |
|---------|-------------|
| **Simplicity** | One URL to remember, one contract to maintain |
| **Stateless** | Each request is self-contained |
| **Idempotent design** | Can safely retry failed requests |
| **Clear ownership** | user_id in path ensures proper scoping |
---
## The 5-Step Deterministic Flow
Every request follows this exact sequence. No shortcuts, no variations.
```
┌─────────────────────────────────────────────────────────────┐
│ Step 1: VALIDATE REQUEST │
│ • Check required fields (message) │
│ • Validate field types and constraints │
│ • Return 400 if invalid │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Step 2: AUTHENTICATE USER │
│ • Verify JWT from Authorization header │
│ • Extract user_id from token │
│ • Verify path user_id matches token user_id │
│ • Return 401/403 if unauthorized │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Step 3: RESOLVE CONVERSATION │
│ • If conversation_id provided: load existing │
│ • If not provided: create new conversation │
│ • Verify conversation ownership │
│ • Return 404 if conversation not found │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Step 4: EXECUTE AGENT │
│ • Build context from conversation history │
│ • Add user message to context │
│ • Call agent runner with context │
│ • Persist user message + agent response │
│ • Return 503 if agent fails │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Step 5: RETURN RESPONSE │
│ • Format structured response │
│ • Include conversation_id for continuation │
│ • Return 200 with ChatResponse │
└─────────────────────────────────────────────────────────────┘
```
---
## Implementation Workflow
### Step 1: Define Request/Response Schemas
See `references/api-contract.md` for complete schemas.
```python
# schemas/chat.py
from pydantic import BaseModel, Field
from typing import Optional
from datetime import datetime
class ChatRequest(BaseModel):
"""Incoming chat request."""
message: str = Field(..., min_length=1, max_length=10000)
conversation_id: Optional[str] = Field(
None,
description="Existing conversation ID, or omit to create new"
)
model: Optional[str] = Field("gpt-4", description="Model to use")
class ChatResponse(BaseModel):
"""Chat API response."""
conversation_id: str
message: str
role: str = "assistant"
created_at: datetime
usage: Optional[dict] = None
```
### Step 2: Create the Router
See `references/request-flow.md` for detailed implementation.
```python
# routers/chat.py
from fastapi import APIRouter, Depends, HTTPException, status
router = APIRouter(prefix="/api", tags=["chat"])
@router.post("/{user_id}/chat", response_model=ChatResponse)
async def chat(
user_id: str,
request: ChatRequest,
current_user: AuthenticatedUser = Depends(get_current_user),
session: Session = Depends(get_session),
agent: AgentRunner = Depends(get_agent_runner)
):
"""
Single chat endpoint with deterministic flow.
1. Validate (handled by Pydantic)
2. Authenticate (handled by dependency)
3. Resolve conversation
4. Execute agent
5. Return response
"""
# Step 2: Verify user_id matches authenticated user
if user_id != current_user.user_id:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Cannot access another user's chat"
)
# Step 3: Resolve conversation
conversation_id = await resolve_conversation(
session=session,
user_id=user_id,
conversation_id=request.conversation_id
)
# Step 4: Execute agent
response = await execute_agent(
session=session,
agent=agent,
conversation_id=conversation_id,
user_id=user_id,
message=request.message,
model=request.model
)
# Step 5: Return response
return response
```
### Step 3: Implement Conversation Resolution
```python
# services/conversation.py
async def resolve_conversation(
session: Session,
user_id: str,
conversation_id: Optional[str]
) -> str:
"""
Resolve or create conversation.
- If conversation_id provided: verify exists and owned by user
- If not provided: create new conversation
Returns: conversation_id (existing or new)
"""
if conversation_id:
# Load existing
conv = get_conversation(session, conversation_id, user_id)
if not conv:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Conversation not found"
)
return conv.id
else:
# Create new
conv = create_conversation(session, user_id=user_id)
return conv.id
```
### Step 4: Implement Agent Execution
```python
# services/agent.py
async def execute_agent(
session: Session,
agent: AgentRunner,
conversation_id: str,
user_id: str,
message: str,
model: str
) -> ChatResponse:
"""
Execute agent with conversation context.
1. Load conversation history
2. Add user message
3. Call agent
4. Persist response
5. Return structured response
"""
# Load context
history = get_messages(session, conversation_id, user_id)
context = [{"role": m.role, "content": m.content} for m in history]
# Add user message
add_message(session, conversation_id, user_id, "user", message)
context.append({"role": "user", "content": message})
try:
# Call agent
result = await agent.run(messages=context, model=model)
# Persist response
add_message(session, conversation_id, user_id, "assistant", result.content)
return ChatResponse(
conversation_id=conversation_id,
message=result.content,
role="assistant",
created_at=datetime.now(timezone.utc),
usage=result.usage
)
except AgentError as e:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail=f"Agent error: {str(e)}"
)
```
---
## Error Handling
See `references/error-handling.md` for complete patterns.
| Step | Error | Status | Response |
|------|-------|--------|----------|
| 1. Validate | Invalid request | 400 | `{"detail": "Field X is required"}` |
| 2. Auth | Missing token | 401 | `{"detail": "Authentication required"}` |
| 2. Auth | Wrong user | 403 | `{"detail": "Cannot access another user's chat"}` |
| 3. Resolve | Conv not found | 404 | `{"detail": "Conversation not found"}` |
| 4. Execute | Agent fails | 503 | `{"detail": "Agent error: ..."}` |
| * | Unexpected | 500 | `{"detail": "Internal server error"}` |
---
## Idempotency Considerations
For safe retries, consider adding request deduplication:
```python
class ChatRequest(BaseModel):
message: str
conversation_id: Optional[str] = None
request_id: Optional[str] = Field(
None,
description="Client-generated UUID for idempotency"
)
```
If `request_id` was seen recently, return cached response instead of re-executing.
---
## Output Checklist
Before delivering implementation:
- [ ] ChatRequest schema with message, conversation_id, model
- [ ] ChatResponse schema with conversation_id, message, role, created_at
- [ ] POST /{user_id}/chat endpoint
- [ ] Path user_id validated against token user_id
- [ ] Conversation resolution (create or load)
- [ ] Agent execution with context
- [ ] Message persistence (user + assistant)
- [ ] Error handling for all 5 steps
- [ ] Consistent error response format
---
## Reference Files
| File | When to Read |
|------|--------------|
| `references/api-contract.md` | Complete request/response schemas and examples |
| `references/request-flow.md` | Detailed implementation of each step |
| `references/error-handling.md` | Error codes, formats, and recovery patterns |
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!