File size: 7,495 Bytes
d347708
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Read Agent is an AI-powered code analysis assistant that uses OpenAI-compatible APIs with the ReAct (Reasoning + Acting) pattern for iterative code exploration. It provides both CLI and Web interfaces.

## Common Commands

### Running the Application

```bash

# CLI interface (interactive terminal)

python main.py



# CLI with specific code directory

python main.py --code-dir /path/to/code



# CLI with multiple API keys (comma-separated)

python main.py --api-key "key1,key2,key3"



# Web server (default port 7860)

python app.py



# Web server with debug mode

DEBUG=true python app.py

```

### Docker

```bash

# Using docker-compose

docker-compose up -d



# Build and run manually

docker build -t read-agent .

docker run -p 7860:7860 read-agent

```

### Testing

```bash

pytest                    # Run tests

pytest --cov            # Run with coverage

```

### Dependencies

```bash

pip install -r requirements.txt

```

## Architecture

### Core Pattern: ReAct Loop

The ReadAgent (src/agent.py) implements a ReAct (Reasoning + Acting) pattern:
1. LLM generates a "thought" about what to do next
2. LLM specifies an "action" using available tools (read_file, search_code, etc.)
3. ToolExecutor executes the action and returns observations
4. Loop continues until the LLM decides it has enough information
5. Final answer is generated based on accumulated observations

This pattern enables iterative exploration without requiring all context upfront.

### Multi API Key Rotation (ApiKeyManager)

**src/api_key_manager.py** - ApiKeyManager class
- Manages multiple API keys for load balancing and reliability
- Round-robin rotation across keys
- Thread-safe operations with locks
- Tracks statistics: request count, success rate, errors
- Global singleton pattern via `get_global_manager()` or `init_manager()`

**Usage:**
```python

from src.api_key_manager import ApiKeyManager



# Single key

manager = ApiKeyManager("sk-xxx")



# Multiple keys (comma-separated)

manager = ApiKeyManager("sk-key1,sk-key2,sk-key3")



# Get next key (round-robin)

key = manager.get_key()



# Record results

manager.record_success(key)

manager.record_error(key, "Error message")



# Get statistics

stats = manager.get_stats()

```

**Integration with ReadAgent:**
- ReadAgent accepts `api_key_manager` parameter
- If provided, uses ApiKeyManager to get keys via rotation
- Records success/failure statistics automatically
- Falls back to legacy single-key mode if no manager provided

### Memory Management

To prevent context expansion across multiple steps, the agent uses a Memory dataclass:

```python

@dataclass

class Memory:

    file_path: str          # File being analyzed

    overview: str           # One-sentence summary

    key_definitions: List[str]  # Key function/class names

    core_logic: str         # Core logic description

    dependencies: List[str] # Dependencies

    needed_info: str        # Information to verify

```

After reading a file, the agent creates a Memory object instead of keeping full file content. Subsequent tool calls can reference previously analyzed files without re-reading them.

### Key Components

**src/agent.py** - ReadAgent class
- Main orchestration of ReAct loop
- Manages Memory objects to optimize context
- Supports streaming output via `ask(stream=True)`
- Batch action support for parallel independent operations
- Integrates with ApiKeyManager for multi-key rotation

**src/searcher.py** - CodeSearcher class
- Provides all file/code interaction tools
- Integrates with CodeIndex for fast keyword/symbol search
- Tools: read_file, find_files, search_code, find_by_ext, list_dir, get_file_info, get_dir_tree

**src/index.py** - CodeIndex class
- Inverted index for fast code search
- Lazy building: builds on first search if not exists
- Supports both keyword search and symbol extraction
- Tokenization handles camelCase, PascalCase, snake_case



**src/repo_manager.py** - RepoManager class

- Downloads GitHub repos as ZIP files

- Skip detection: won't re-download existing repos unless forced

- Parallel sync support (threading)

- Configured via environment variables (REPO_1_URL, REPO_2_URL, etc.)



**src/session_storage.py** - SessionStorage class

- SQLite-based persistent storage for sessions

- Thread-safe with locks

- Stores: session metadata, conversation history, memories

- Cleanup of old sessions



**prompts.py** - Prompt configuration

- ReAct format instructions

- Information need tree construction strategy

- Priority-based search (docs → config → code)

- Recursive validation protocol



### Entry Points



1. **main.py** - CLI interface with interactive commands (quit, clear, status, help)

2. **app.py** - Flask web application with REST APIs



### Session Isolation



Each user session (web) has:

- Independent ReadAgent instance

- Separate Memory objects

- Isolated conversation history

- SQLite persistence (can be restored)

- Shared ApiKeyManager instance (for efficient key rotation)



### Streaming Support



The agent supports streaming responses (`STREAM_OUTPUT=true`):
- Thoughts and actions stream in real-time
- Final answer detection via special tokens
- Provides immediate feedback during long-running analysis

## Environment Variables

### API Configuration
- `OPENAI_API_KEY` - Required (can be multiple keys separated by commas)
- `OPENAI_BASE_URL` - Default: https://api.openai.com/v1
- `OPENAI_MODEL` - Default: gpt-4

### Repository Configuration
- `CODE_DIR` - Default: ./repos
- `REPO_SYNC_ON_STARTUP` - Default: true
- `REPO_1_URL`, `REPO_2_URL`, etc. - GitHub repo URLs
- `REPO_1_NAME`, `REPO_1_BRANCH`, etc. - Per-repo settings

### Agent Configuration
- `MAX_STEPS` - Maximum reasoning steps (default: 10)
- `TREE_DEPTH` - Directory tree preload depth (default: 3)
- `STREAM_OUTPUT` - Enable streaming (default: true)
- `WEB_PORT` - Web server port (default: 7860)
- `DEBUG` - Debug mode (default: false)

## API Endpoints (app.py)

### Question API
- `POST /api/ask` - Main question endpoint (supports streaming via query param or JSON field)

### Session Management
- `POST /api/session/new` - Create new session
- `POST /api/session/clear` - Clear session(s)
- `GET /status` - Service status

### Repository Management
- `GET /api/repos` - List repositories
- `POST /api/repos/sync` - Sync repositories
- `GET /api/repos/config` - Get repository configuration
- `POST /api/repos/clear` - Clear all repositories

### API Key Management
- `GET /api/api-keys/stats` - Get API key usage statistics
- `POST /api/api-keys/reset-stats` - Reset API key statistics

### Health Check
- `GET /health` - Health check
- `GET /prompt` - Return system prompt

## Technical Notes

- **Pure Python** - Uses only standard library (urllib) and minimal dependencies (Flask, python-dotenv)
- **No async/await** - Uses threading for parallel operations
- **SQLite** for session persistence (file-based, no external DB required)
- **Symbol extraction** for Python and JavaScript in CodeIndex (AST-based)
- **ReAct format** - LLM outputs structured JSON with "thought" and "action" fields
- **Thread-safe API Key Management** - Uses locks for concurrent access to ApiKeyManager