# Core Agent Loop API

FastAPI application providing Server-Sent Events (SSE) endpoint for Claude SDK agent interactions.

## Project Structure

```
core_agent_loop/
├── app/
│   ├── __init__.py
│   ├── main.py                 # FastAPI application entry point
│   └── router/
│       ├── __init__.py
│       └── agent.py            # Agent loop SSE endpoint
├── config.py                   # Configuration settings
├── add_keyword_test.py         # Original test script
├── requirements.txt            # Python dependencies
└── env.local                   # Configuration file (rename to .env)
```

## Setup

1. **Install dependencies:**
   ```bash
   pip install -r requirements.txt
   ```

2. **Configure environment:**
   ```bash
   cp env.local .env
   # Edit .env to add your Langfuse credentials if needed
   ```

3. **Ensure Claude CLI is installed and configured:**
   ```bash
   claude --version
   ```

## Running the Server

### Using Docker Compose (Recommended):
```bash
# Start all services (FastAPI on 8334, Claude-Mem Manager on 37777, File API on 38888)
docker-compose up -d

# View logs
docker-compose logs -f

# Stop services
docker-compose down
```

The FastAPI server will be available at `http://localhost:8334`  
The Claude-Mem Manager UI will be available at `http://localhost:37777/switch_user`  
All other traffic on port 37777 will be proxied to the active claude-mem worker  
The File API service will be available at `http://localhost:38888`
The CLI wheel server will be available at `http://localhost:11113`

### Using Python directly:
```bash
python -m app.main
```

### Using Uvicorn:
```bash
uvicorn app.main:app --reload --host 0.0.0.0 --port 8334
```

The server will start at `http://localhost:8334`

## CLI Auto Upgrade

Install from PyPI:

```bash
python -m pip install --upgrade pip
python -m pip install --upgrade luckee-cli
```

If you want to validate a `dev` publish first, install from TestPyPI:

```bash
python -m pip install --upgrade \
  --index-url https://test.pypi.org/simple/ \
  --extra-index-url https://pypi.org/simple \
  luckee-cli
```

For the staging CLI, set the environment before login/use:

```bash
export LUCKEE_ENV=staging
```

This selects both the staging OAuth API (`staging-user-api.motse.ai`) and the staging
frontend automatically. `LUCKEE_OAUTH_BASE_URL` / `LUCKEE_FRONTEND` can still override
individual URLs when needed.

CLI auth helpers:

```bash
luckee login
luckee logout
```

Published defaults:
- `LUCKEE_ENV=staging` → OAuth API `staging-user-api.motse.ai`, frontend `luckee-frontend-staging-…`
- `LUCKEE_ENV=prod` (default) → OAuth API `user-api.motse.ai`, frontend `motse.ai`
- `dev` branch builds default WebSocket endpoint to `wss://core-agent-loop-dev-950663559455.us-central1.run.app/api/v2/agent/ws`
- `main` branch builds default WebSocket endpoint to `wss://core-agent-loop-950663559455.us-central1.run.app/api/v2/agent/ws`
- `dev` branch builds default File API base URL to `https://file-api-dev-950663559455.us-central1.run.app`
- `main` branch builds default File API base URL to `https://file-api-main-950663559455.us-central1.run.app`

Upgrade the installed CLI:

```bash
luckee --upgrade
```

Or while inside interactive CLI:

```text
/upgrade
```

## CLI Development

For local `luckee` CLI development and packaging validation, use the dedicated guide:

- [CLI Development Guide](docs/CLI_DEVELOPMENT.md)

Shortest repeatable local validation loop:

```powershell
conda activate core_agent_loop
python scripts/validate_cli_dev_loop.py
```

That helper repairs stale editable CLI metadata, validates both local entrypoints, and builds a fresh wheel.
Use `python scripts/validate_cli_dev_loop.py --with-pipx --remote-smoke ...` when you also want packaged remote validation.

## API Endpoints

### Root
- **GET** `/` - API information and available endpoints

### Health Check
- **GET** `/health` - Health check endpoint

### Agent Test
- **GET** `/api/agent/test` - Test the agent router

### Agent Stream (SSE)
- **POST** `/api/agent/stream` - Stream agent responses via Server-Sent Events

**Request Body:**
```json
{
  "query": "add a keyword test_keyword_1",
  "thread_id": null,
  "user_id": "dylan",
  "working_dir": null,
  "system_prompt": null
}
```

**Response:** Server-Sent Events stream with structured state messages.

### File API (Port 38888)
- **GET** `/api/v2/resume_thread` - Resume a thread by streaming messages (SSE)
- **GET** `/api/v2/list_threads` - List all thread IDs for a user
- **GET** `/api/v2/fetch_files` - Fetch files from user directories

**Resume Thread (SSE) Query Parameters:**
- `thread_id`: Thread ID (must be a valid UUID)
- `user_id`: User ID

**Resume Thread Example:**
```bash
curl -N "http://localhost:38888/api/v2/resume_thread?thread_id=550e8400-e29b-41d4-a716-446655440000&user_id=dylan"
```

The stream always starts with a config message containing metadata from `working_dir/metadata.json`, followed by all messages from `streaming_messages.jsonl`, and ends with a completion event.

**List Threads Query Parameters:**
- `user_id`: User ID

**List Threads Example:**
```bash
curl "http://localhost:38888/api/v2/list_threads?user_id=dylan"
```

**Fetch Files Query Parameters:**
- `type`: Type of file to fetch (`csv`, `json`, or `json_folder`)
- `thread_id`: Thread ID (must be a valid UUID string)
- `path`: Relative path to the file from working_dir
- `user_id`: User ID

**Examples:**

Fetch a JSON file:
```bash
curl "http://localhost:38888/api/v2/fetch_files?type=json&thread_id=550e8400-e29b-41d4-a716-446655440000&path=data/config.json&user_id=dylan"
```

Fetch a CSV file:
```bash
curl "http://localhost:38888/api/v2/fetch_files?type=csv&thread_id=550e8400-e29b-41d4-a716-446655440000&path=data/report.csv&user_id=dylan"
```

Fetch all JSON files from a folder:
```bash
curl "http://localhost:38888/api/v2/fetch_files?type=json_folder&thread_id=550e8400-e29b-41d4-a716-446655440000&path=data/json_files&user_id=dylan"
```

**Response Format:**
- For `csv`/`json`: Returns content of the file
- For `json_folder`: Returns a dict mapping filename to content for all `*.json` files

**Security:**
- Path traversal protection is enforced
- Files must exist under `/data/{user_id}/projects/{thread_id}/working_dir/{path}`

## Session Management

The agent supports session resumption based on `thread_id`. The project state (including the Claude SDK session ID) is stored in `/data/${user_id}/projects/${thread_id}/working_dir/metadata.json`.

To resume a session, include the `thread_id` in subsequent requests:

```json
{
  "query": "continue with the next task",
  "thread_id": "previous_thread_id",
  "user_id": "dylan"
}
```

If a `thread_id` is provided but no existing session is found in the project metadata, the API will return an error.

## Development

### Architecture Documentation
For detailed information about the system architecture, modules, and design patterns, see:
- [Architecture Documentation](docs/ARCHITECTURE.md) - Complete system architecture overview

### Original Test Script
The original CLI test script is still available:
```bash
python add_keyword_test.py --query "add a keyword test_keyword_1"
```

## License

MIT

