aloop 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of aloop might be problematic. Click here for more details.

Files changed (92) hide show
  1. aloop-0.1.0/LICENSE +21 -0
  2. aloop-0.1.0/MANIFEST.in +5 -0
  3. aloop-0.1.0/PKG-INFO +246 -0
  4. aloop-0.1.0/README.md +197 -0
  5. aloop-0.1.0/agent/__init__.py +0 -0
  6. aloop-0.1.0/agent/agent.py +182 -0
  7. aloop-0.1.0/agent/base.py +406 -0
  8. aloop-0.1.0/agent/context.py +126 -0
  9. aloop-0.1.0/agent/todo.py +149 -0
  10. aloop-0.1.0/agent/tool_executor.py +54 -0
  11. aloop-0.1.0/agent/verification.py +135 -0
  12. aloop-0.1.0/aloop.egg-info/PKG-INFO +246 -0
  13. aloop-0.1.0/aloop.egg-info/SOURCES.txt +90 -0
  14. aloop-0.1.0/aloop.egg-info/dependency_links.txt +1 -0
  15. aloop-0.1.0/aloop.egg-info/entry_points.txt +2 -0
  16. aloop-0.1.0/aloop.egg-info/requires.txt +26 -0
  17. aloop-0.1.0/aloop.egg-info/top_level.txt +9 -0
  18. aloop-0.1.0/cli.py +19 -0
  19. aloop-0.1.0/config.py +146 -0
  20. aloop-0.1.0/docs/configuration.md +124 -0
  21. aloop-0.1.0/docs/examples.md +161 -0
  22. aloop-0.1.0/docs/extending.md +159 -0
  23. aloop-0.1.0/docs/memory-management.md +245 -0
  24. aloop-0.1.0/docs/packaging.md +104 -0
  25. aloop-0.1.0/examples/agent_example.py +75 -0
  26. aloop-0.1.0/examples/memory_persistence_demo.py +132 -0
  27. aloop-0.1.0/examples/web_fetch_example.py +59 -0
  28. aloop-0.1.0/interactive.py +865 -0
  29. aloop-0.1.0/llm/__init__.py +51 -0
  30. aloop-0.1.0/llm/base.py +26 -0
  31. aloop-0.1.0/llm/compat.py +226 -0
  32. aloop-0.1.0/llm/content_utils.py +309 -0
  33. aloop-0.1.0/llm/litellm_adapter.py +450 -0
  34. aloop-0.1.0/llm/message_types.py +245 -0
  35. aloop-0.1.0/llm/model_manager.py +265 -0
  36. aloop-0.1.0/llm/retry.py +95 -0
  37. aloop-0.1.0/main.py +246 -0
  38. aloop-0.1.0/memory/__init__.py +20 -0
  39. aloop-0.1.0/memory/compressor.py +554 -0
  40. aloop-0.1.0/memory/manager.py +538 -0
  41. aloop-0.1.0/memory/serialization.py +82 -0
  42. aloop-0.1.0/memory/short_term.py +88 -0
  43. aloop-0.1.0/memory/token_tracker.py +203 -0
  44. aloop-0.1.0/memory/types.py +51 -0
  45. aloop-0.1.0/pyproject.toml +107 -0
  46. aloop-0.1.0/setup.cfg +4 -0
  47. aloop-0.1.0/test/test_basic.py +45 -0
  48. aloop-0.1.0/test/test_code_navigator.py +770 -0
  49. aloop-0.1.0/test/test_explore_tool.py +139 -0
  50. aloop-0.1.0/test/test_litellm_adapter.py +204 -0
  51. aloop-0.1.0/test/test_memory.py +110 -0
  52. aloop-0.1.0/test/test_model_setup_session.py +74 -0
  53. aloop-0.1.0/test/test_notify_integration.py +32 -0
  54. aloop-0.1.0/test/test_notify_tool.py +127 -0
  55. aloop-0.1.0/test/test_parallel_execute_tool.py +256 -0
  56. aloop-0.1.0/test/test_ralph_loop.py +285 -0
  57. aloop-0.1.0/test/test_shell_background.py +348 -0
  58. aloop-0.1.0/test/test_slash_command_autocomplete.py +72 -0
  59. aloop-0.1.0/test/test_smart_edit.py +344 -0
  60. aloop-0.1.0/test/test_smart_edit_integration.py +93 -0
  61. aloop-0.1.0/test/test_tool_size_limits.py +154 -0
  62. aloop-0.1.0/test/test_web_fetch.py +139 -0
  63. aloop-0.1.0/tools/__init__.py +6 -0
  64. aloop-0.1.0/tools/advanced_file_ops.py +557 -0
  65. aloop-0.1.0/tools/base.py +51 -0
  66. aloop-0.1.0/tools/calculator.py +50 -0
  67. aloop-0.1.0/tools/code_navigator.py +975 -0
  68. aloop-0.1.0/tools/explore.py +254 -0
  69. aloop-0.1.0/tools/file_ops.py +150 -0
  70. aloop-0.1.0/tools/git_tools.py +791 -0
  71. aloop-0.1.0/tools/notify.py +69 -0
  72. aloop-0.1.0/tools/parallel_execute.py +420 -0
  73. aloop-0.1.0/tools/session_manager.py +205 -0
  74. aloop-0.1.0/tools/shell.py +147 -0
  75. aloop-0.1.0/tools/shell_background.py +470 -0
  76. aloop-0.1.0/tools/smart_edit.py +491 -0
  77. aloop-0.1.0/tools/todo.py +130 -0
  78. aloop-0.1.0/tools/web_fetch.py +673 -0
  79. aloop-0.1.0/tools/web_search.py +61 -0
  80. aloop-0.1.0/utils/__init__.py +15 -0
  81. aloop-0.1.0/utils/logger.py +105 -0
  82. aloop-0.1.0/utils/model_pricing.py +49 -0
  83. aloop-0.1.0/utils/runtime.py +75 -0
  84. aloop-0.1.0/utils/terminal_ui.py +422 -0
  85. aloop-0.1.0/utils/tui/__init__.py +39 -0
  86. aloop-0.1.0/utils/tui/command_registry.py +49 -0
  87. aloop-0.1.0/utils/tui/components.py +306 -0
  88. aloop-0.1.0/utils/tui/input_handler.py +393 -0
  89. aloop-0.1.0/utils/tui/model_ui.py +204 -0
  90. aloop-0.1.0/utils/tui/progress.py +292 -0
  91. aloop-0.1.0/utils/tui/status_bar.py +178 -0
  92. aloop-0.1.0/utils/tui/theme.py +165 -0
aloop-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Yixin Luo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,5 @@
1
+ # Include important files in the package
2
+ include README.md
3
+ include LICENSE
4
+ recursive-include docs *.md
5
+ recursive-include examples *.py *.md
aloop-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,246 @@
1
+ Metadata-Version: 2.4
2
+ Name: aloop
3
+ Version: 0.1.0
4
+ Summary: General AI Agent System
5
+ Author-email: luohaha <luoyixin6688@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/luohaha/aloop
8
+ Project-URL: Documentation, https://github.com/luohaha/aloop#readme
9
+ Project-URL: Repository, https://github.com/luohaha/aloop
10
+ Project-URL: Issues, https://github.com/luohaha/aloop/issues
11
+ Keywords: ai,agent,llm,claude,gpt,gemini,loop,planning
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Requires-Python: >=3.12
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: ddgs>=1.0.0
24
+ Requires-Dist: rich>=13.0.0
25
+ Requires-Dist: prompt_toolkit>=3.0.0
26
+ Requires-Dist: httpx>=0.28.0
27
+ Requires-Dist: trafilatura>=2.0.0
28
+ Requires-Dist: lxml>=5.0.0
29
+ Requires-Dist: aiofiles>=24.1.0
30
+ Requires-Dist: litellm>=1.30.0
31
+ Requires-Dist: PyYAML>=6.0
32
+ Requires-Dist: tiktoken>=0.5.0
33
+ Requires-Dist: tenacity>=8.2.0
34
+ Requires-Dist: tree-sitter<0.22.0,>=0.21.0
35
+ Requires-Dist: tree-sitter-languages<1.11.0,>=1.8.0
36
+ Requires-Dist: croniter>=1.3.0
37
+ Provides-Extra: dev
38
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
39
+ Requires-Dist: pytest-asyncio>=0.24.0; extra == "dev"
40
+ Requires-Dist: black>=23.0.0; extra == "dev"
41
+ Requires-Dist: isort>=5.12.0; extra == "dev"
42
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
43
+ Requires-Dist: ruff>=0.6.0; extra == "dev"
44
+ Requires-Dist: pre-commit>=3.0.0; extra == "dev"
45
+ Requires-Dist: types-aiofiles>=25.1.0; extra == "dev"
46
+ Requires-Dist: types-croniter>=1.3.0; extra == "dev"
47
+ Requires-Dist: types-PyYAML>=6.0; extra == "dev"
48
+ Dynamic: license-file
49
+
50
+ <div align="center">
51
+ <picture>
52
+ <img alt="ALOOP" src="docs/assets/logo.svg" width="440">
53
+ </picture>
54
+
55
+ **One loop is all you need.**
56
+
57
+ aloop is an AI agent built on a single, unified loop. Planning, parallel sub-agents,
58
+ self-verification — everything folds into the same loop, chosen autonomously by the
59
+ agent itself, not by a hardcoded workflow. Simple architecture, emergent capability.
60
+
61
+
62
+ </div>
63
+
64
+ ## Installation
65
+
66
+ Prerequisites: Python 3.12+ and [uv](https://github.com/astral-sh/uv).
67
+
68
+ ```bash
69
+ git clone https://github.com/luohaha/aloop.git
70
+ cd aloop
71
+ ./scripts/bootstrap.sh
72
+ ```
73
+
74
+ ## Quick Start
75
+
76
+ ### 1. Configure Models
77
+
78
+ On first run, `~/.aloop/models.yaml` is created with a template. Edit it to add your provider and API key:
79
+
80
+ ```yaml
81
+ models:
82
+ openai/gpt-4o:
83
+ api_key: sk-...
84
+
85
+ anthropic/claude-3-5-sonnet-20241022:
86
+ api_key: sk-ant-...
87
+
88
+ ollama/llama2:
89
+ api_base: http://localhost:11434
90
+
91
+ default: openai/gpt-4o
92
+ ```
93
+
94
+ See [LiteLLM Providers](https://docs.litellm.ai/docs/providers) for the full list.
95
+
96
+ ### 2. Run
97
+
98
+ ```bash
99
+ # Interactive mode
100
+ aloop
101
+
102
+ # Single task (returns raw result)
103
+ aloop --task "Calculate 123 * 456"
104
+
105
+ # Resume last session
106
+ aloop --resume
107
+
108
+ # Resume specific session (ID prefix)
109
+ aloop --resume a1b2c3d4
110
+ ```
111
+
112
+ ## CLI Reference
113
+
114
+ | Flag | Short | Description |
115
+ |------|-------|-------------|
116
+ | `--task TEXT` | `-t` | Run a single task and exit |
117
+ | `--model ID` | `-m` | LiteLLM model ID to use |
118
+ | `--resume [ID]` | `-r` | Resume a session (`latest` if no ID given) |
119
+ | `--verbose` | `-v` | Enable verbose logging to `~/.aloop/logs/` |
120
+
121
+ ## Interactive Commands
122
+
123
+ ### Slash Commands
124
+
125
+ | Command | Description |
126
+ |---------|-------------|
127
+ | `/help` | Show help |
128
+ | `/clear` | Clear conversation and start fresh |
129
+ | `/stats` | Show memory and token usage statistics |
130
+ | `/resume [id]` | List or resume a previous session |
131
+ | `/model` | Pick a model (arrow keys + Enter) |
132
+ | `/model edit` | Open `~/.aloop/models.yaml` in editor (auto-reload on save) |
133
+ | `/theme` | Toggle dark/light theme |
134
+ | `/verbose` | Toggle thinking display |
135
+ | `/compact` | Toggle compact output |
136
+ | `/exit` | Exit (also `/quit`) |
137
+
138
+ ### Keyboard Shortcuts
139
+
140
+ | Key | Action |
141
+ |-----|--------|
142
+ | `/` | Command autocomplete |
143
+ | `Ctrl+C` | Cancel current operation |
144
+ | `Ctrl+L` | Clear screen |
145
+ | `Ctrl+T` | Toggle thinking display |
146
+ | `Ctrl+S` | Show quick stats |
147
+ | Up/Down | Navigate command history |
148
+
149
+ ## How It Works
150
+
151
+ **Agent loop**: The agent follows a Think-Act-Observe cycle. It reasons about the task, selects a tool, observes the result, and repeats until it has an answer. Planning, sub-agent dispatch, and tool use all happen inside this single loop.
152
+
153
+ **Ralph verification**: For single tasks (`--task`), an outer loop verifies the agent's answer against the original task. If incomplete, feedback is injected and the agent loop re-enters. Configurable via `RALPH_LOOP_MAX_ITERATIONS` (default: 3).
154
+
155
+ **Memory compression**: When context grows past a token threshold, older messages are compressed via LLM summarization. Recent messages are kept at full fidelity. Strategies: `sliding_window` (default), `selective`, `deletion`.
156
+
157
+ **Session persistence**: Conversations are saved as YAML files under `~/.aloop/sessions/`. Resume with `--resume` or `/resume`.
158
+
159
+ ## Tools
160
+
161
+ | Tool | Description |
162
+ |------|-------------|
163
+ | `read_file` | Read file contents |
164
+ | `write_file` | Write content to a file |
165
+ | `search_files` | Search for files by name |
166
+ | `edit_file` | Exact string replacement in files |
167
+ | `smart_edit` | LLM-assisted file editing |
168
+ | `glob_files` | Glob pattern file matching |
169
+ | `grep_content` | Regex search in file contents |
170
+ | `code_navigator` | AST-based code navigation (tree-sitter) |
171
+ | `calculate` | Evaluate expressions / run Python code |
172
+ | `shell` | Execute shell commands |
173
+ | `shell_task_status` | Check background shell task status |
174
+ | `web_search` | Web search (DuckDuckGo) |
175
+ | `web_fetch` | Fetch and extract web page content |
176
+ | `explore_context` | Explore project structure and context |
177
+ | `parallel_execute` | Run multiple tool calls in parallel |
178
+ | `notify` | Send email notifications (Resend) |
179
+ | `manage_todo_list` | Manage a task/todo list |
180
+
181
+ ## Project Structure
182
+
183
+ ```
184
+ aloop/
185
+ ├── main.py # Entry point (argparse)
186
+ ├── cli.py # CLI wrapper (`aloop` entry point)
187
+ ├── interactive.py # Interactive session, model setup, TUI
188
+ ├── config.py # Runtime config (~/.aloop/config)
189
+ ├── agent/
190
+ │ ├── base.py # BaseAgent (ReAct + Ralph loops)
191
+ │ ├── agent.py # LoopAgent
192
+ │ ├── verification.py # LLMVerifier for Ralph loop
193
+ │ ├── context.py # Context injection (cwd, platform, date)
194
+ │ ├── tool_executor.py # Tool execution engine
195
+ │ └── todo.py # Todo list data structure
196
+ ├── llm/
197
+ │ ├── litellm_adapter.py # LiteLLM adapter (100+ providers)
198
+ │ ├── model_manager.py # Model config from ~/.aloop/models.yaml
199
+ │ ├── retry.py # Retry with exponential backoff
200
+ │ └── message_types.py # LLMMessage, LLMResponse, ToolCall
201
+ ├── memory/
202
+ │ ├── manager.py # Memory orchestrator + persistence
203
+ │ ├── compressor.py # LLM-driven compression
204
+ │ ├── short_term.py # Short-term memory (sliding window)
205
+ │ ├── token_tracker.py # Token counting + cost tracking
206
+ │ ├── types.py # Core data structures
207
+ │ └── store/
208
+ │ └── yaml_file_memory_store.py # YAML session persistence
209
+ ├── tools/ # 18 tool implementations
210
+ ├── utils/
211
+ │ ├── tui/ # TUI components (input, themes, status bar)
212
+ │ ├── logger.py # Logging setup
213
+ │ └── model_pricing.py # Model pricing data
214
+ ├── docs/ # Documentation
215
+ ├── test/ # Tests
216
+ ├── scripts/ # Dev scripts (bootstrap.sh, dev.sh)
217
+ └── rfc/ # RFC design documents
218
+ ```
219
+
220
+ ## Configuration
221
+
222
+ Runtime settings live in `~/.aloop/config` (auto-created). Key settings:
223
+
224
+ | Setting | Default | Description |
225
+ |---------|---------|-------------|
226
+ | `MAX_ITERATIONS` | `1000` | Maximum agent loop iterations |
227
+ | `TOOL_TIMEOUT` | `600` | Tool execution timeout (seconds) |
228
+ | `RALPH_LOOP_MAX_ITERATIONS` | `3` | Max verification attempts |
229
+ | `MEMORY_ENABLED` | `true` | Enable memory management |
230
+ | `MEMORY_COMPRESSION_THRESHOLD` | `60000` | Token threshold for compression |
231
+ | `MEMORY_SHORT_TERM_SIZE` | `100` | Messages kept at full fidelity |
232
+ | `RETRY_MAX_ATTEMPTS` | `3` | Rate-limit retry attempts |
233
+
234
+ See [Configuration Guide](docs/configuration.md) for all settings.
235
+
236
+ ## Documentation
237
+
238
+ - [Configuration](docs/configuration.md) -- model setup, runtime settings, custom endpoints
239
+ - [Examples](docs/examples.md) -- usage patterns and programmatic API
240
+ - [Memory Management](docs/memory-management.md) -- compression, persistence, token tracking
241
+ - [Extending](docs/extending.md) -- adding tools, agents, LLM providers
242
+ - [Packaging](docs/packaging.md) -- building, publishing, Docker
243
+
244
+ ## License
245
+
246
+ MIT License
aloop-0.1.0/README.md ADDED
@@ -0,0 +1,197 @@
1
+ <div align="center">
2
+ <picture>
3
+ <img alt="ALOOP" src="docs/assets/logo.svg" width="440">
4
+ </picture>
5
+
6
+ **One loop is all you need.**
7
+
8
+ aloop is an AI agent built on a single, unified loop. Planning, parallel sub-agents,
9
+ self-verification — everything folds into the same loop, chosen autonomously by the
10
+ agent itself, not by a hardcoded workflow. Simple architecture, emergent capability.
11
+
12
+
13
+ </div>
14
+
15
+ ## Installation
16
+
17
+ Prerequisites: Python 3.12+ and [uv](https://github.com/astral-sh/uv).
18
+
19
+ ```bash
20
+ git clone https://github.com/luohaha/aloop.git
21
+ cd aloop
22
+ ./scripts/bootstrap.sh
23
+ ```
24
+
25
+ ## Quick Start
26
+
27
+ ### 1. Configure Models
28
+
29
+ On first run, `~/.aloop/models.yaml` is created with a template. Edit it to add your provider and API key:
30
+
31
+ ```yaml
32
+ models:
33
+ openai/gpt-4o:
34
+ api_key: sk-...
35
+
36
+ anthropic/claude-3-5-sonnet-20241022:
37
+ api_key: sk-ant-...
38
+
39
+ ollama/llama2:
40
+ api_base: http://localhost:11434
41
+
42
+ default: openai/gpt-4o
43
+ ```
44
+
45
+ See [LiteLLM Providers](https://docs.litellm.ai/docs/providers) for the full list.
46
+
47
+ ### 2. Run
48
+
49
+ ```bash
50
+ # Interactive mode
51
+ aloop
52
+
53
+ # Single task (returns raw result)
54
+ aloop --task "Calculate 123 * 456"
55
+
56
+ # Resume last session
57
+ aloop --resume
58
+
59
+ # Resume specific session (ID prefix)
60
+ aloop --resume a1b2c3d4
61
+ ```
62
+
63
+ ## CLI Reference
64
+
65
+ | Flag | Short | Description |
66
+ |------|-------|-------------|
67
+ | `--task TEXT` | `-t` | Run a single task and exit |
68
+ | `--model ID` | `-m` | LiteLLM model ID to use |
69
+ | `--resume [ID]` | `-r` | Resume a session (`latest` if no ID given) |
70
+ | `--verbose` | `-v` | Enable verbose logging to `~/.aloop/logs/` |
71
+
72
+ ## Interactive Commands
73
+
74
+ ### Slash Commands
75
+
76
+ | Command | Description |
77
+ |---------|-------------|
78
+ | `/help` | Show help |
79
+ | `/clear` | Clear conversation and start fresh |
80
+ | `/stats` | Show memory and token usage statistics |
81
+ | `/resume [id]` | List or resume a previous session |
82
+ | `/model` | Pick a model (arrow keys + Enter) |
83
+ | `/model edit` | Open `~/.aloop/models.yaml` in editor (auto-reload on save) |
84
+ | `/theme` | Toggle dark/light theme |
85
+ | `/verbose` | Toggle thinking display |
86
+ | `/compact` | Toggle compact output |
87
+ | `/exit` | Exit (also `/quit`) |
88
+
89
+ ### Keyboard Shortcuts
90
+
91
+ | Key | Action |
92
+ |-----|--------|
93
+ | `/` | Command autocomplete |
94
+ | `Ctrl+C` | Cancel current operation |
95
+ | `Ctrl+L` | Clear screen |
96
+ | `Ctrl+T` | Toggle thinking display |
97
+ | `Ctrl+S` | Show quick stats |
98
+ | Up/Down | Navigate command history |
99
+
100
+ ## How It Works
101
+
102
+ **Agent loop**: The agent follows a Think-Act-Observe cycle. It reasons about the task, selects a tool, observes the result, and repeats until it has an answer. Planning, sub-agent dispatch, and tool use all happen inside this single loop.
103
+
104
+ **Ralph verification**: For single tasks (`--task`), an outer loop verifies the agent's answer against the original task. If incomplete, feedback is injected and the agent loop re-enters. Configurable via `RALPH_LOOP_MAX_ITERATIONS` (default: 3).
105
+
106
+ **Memory compression**: When context grows past a token threshold, older messages are compressed via LLM summarization. Recent messages are kept at full fidelity. Strategies: `sliding_window` (default), `selective`, `deletion`.
107
+
108
+ **Session persistence**: Conversations are saved as YAML files under `~/.aloop/sessions/`. Resume with `--resume` or `/resume`.
109
+
110
+ ## Tools
111
+
112
+ | Tool | Description |
113
+ |------|-------------|
114
+ | `read_file` | Read file contents |
115
+ | `write_file` | Write content to a file |
116
+ | `search_files` | Search for files by name |
117
+ | `edit_file` | Exact string replacement in files |
118
+ | `smart_edit` | LLM-assisted file editing |
119
+ | `glob_files` | Glob pattern file matching |
120
+ | `grep_content` | Regex search in file contents |
121
+ | `code_navigator` | AST-based code navigation (tree-sitter) |
122
+ | `calculate` | Evaluate expressions / run Python code |
123
+ | `shell` | Execute shell commands |
124
+ | `shell_task_status` | Check background shell task status |
125
+ | `web_search` | Web search (DuckDuckGo) |
126
+ | `web_fetch` | Fetch and extract web page content |
127
+ | `explore_context` | Explore project structure and context |
128
+ | `parallel_execute` | Run multiple tool calls in parallel |
129
+ | `notify` | Send email notifications (Resend) |
130
+ | `manage_todo_list` | Manage a task/todo list |
131
+
132
+ ## Project Structure
133
+
134
+ ```
135
+ aloop/
136
+ ├── main.py # Entry point (argparse)
137
+ ├── cli.py # CLI wrapper (`aloop` entry point)
138
+ ├── interactive.py # Interactive session, model setup, TUI
139
+ ├── config.py # Runtime config (~/.aloop/config)
140
+ ├── agent/
141
+ │ ├── base.py # BaseAgent (ReAct + Ralph loops)
142
+ │ ├── agent.py # LoopAgent
143
+ │ ├── verification.py # LLMVerifier for Ralph loop
144
+ │ ├── context.py # Context injection (cwd, platform, date)
145
+ │ ├── tool_executor.py # Tool execution engine
146
+ │ └── todo.py # Todo list data structure
147
+ ├── llm/
148
+ │ ├── litellm_adapter.py # LiteLLM adapter (100+ providers)
149
+ │ ├── model_manager.py # Model config from ~/.aloop/models.yaml
150
+ │ ├── retry.py # Retry with exponential backoff
151
+ │ └── message_types.py # LLMMessage, LLMResponse, ToolCall
152
+ ├── memory/
153
+ │ ├── manager.py # Memory orchestrator + persistence
154
+ │ ├── compressor.py # LLM-driven compression
155
+ │ ├── short_term.py # Short-term memory (sliding window)
156
+ │ ├── token_tracker.py # Token counting + cost tracking
157
+ │ ├── types.py # Core data structures
158
+ │ └── store/
159
+ │ └── yaml_file_memory_store.py # YAML session persistence
160
+ ├── tools/ # 18 tool implementations
161
+ ├── utils/
162
+ │ ├── tui/ # TUI components (input, themes, status bar)
163
+ │ ├── logger.py # Logging setup
164
+ │ └── model_pricing.py # Model pricing data
165
+ ├── docs/ # Documentation
166
+ ├── test/ # Tests
167
+ ├── scripts/ # Dev scripts (bootstrap.sh, dev.sh)
168
+ └── rfc/ # RFC design documents
169
+ ```
170
+
171
+ ## Configuration
172
+
173
+ Runtime settings live in `~/.aloop/config` (auto-created). Key settings:
174
+
175
+ | Setting | Default | Description |
176
+ |---------|---------|-------------|
177
+ | `MAX_ITERATIONS` | `1000` | Maximum agent loop iterations |
178
+ | `TOOL_TIMEOUT` | `600` | Tool execution timeout (seconds) |
179
+ | `RALPH_LOOP_MAX_ITERATIONS` | `3` | Max verification attempts |
180
+ | `MEMORY_ENABLED` | `true` | Enable memory management |
181
+ | `MEMORY_COMPRESSION_THRESHOLD` | `60000` | Token threshold for compression |
182
+ | `MEMORY_SHORT_TERM_SIZE` | `100` | Messages kept at full fidelity |
183
+ | `RETRY_MAX_ATTEMPTS` | `3` | Rate-limit retry attempts |
184
+
185
+ See [Configuration Guide](docs/configuration.md) for all settings.
186
+
187
+ ## Documentation
188
+
189
+ - [Configuration](docs/configuration.md) -- model setup, runtime settings, custom endpoints
190
+ - [Examples](docs/examples.md) -- usage patterns and programmatic API
191
+ - [Memory Management](docs/memory-management.md) -- compression, persistence, token tracking
192
+ - [Extending](docs/extending.md) -- adding tools, agents, LLM providers
193
+ - [Packaging](docs/packaging.md) -- building, publishing, Docker
194
+
195
+ ## License
196
+
197
+ MIT License
File without changes
@@ -0,0 +1,182 @@
1
+ """Loop agent implementation."""
2
+
3
+ from config import Config
4
+ from llm import LLMMessage
5
+ from utils import terminal_ui
6
+
7
+ from .base import BaseAgent
8
+ from .context import format_context_prompt
9
+
10
+
11
+ class LoopAgent(BaseAgent):
12
+ """Primary agent implementation — one unified loop for all tasks."""
13
+
14
+ SYSTEM_PROMPT = """<role>
15
+ You are a helpful AI assistant that uses tools to accomplish tasks efficiently and reliably.
16
+ </role>
17
+
18
+ <critical_rules>
19
+ IMPORTANT: Always think before acting
20
+ IMPORTANT: Use the most efficient tool for each operation
21
+ IMPORTANT: Manage todo lists for complex multi-step tasks
22
+ IMPORTANT: Mark tasks completed IMMEDIATELY after finishing them
23
+ </critical_rules>
24
+
25
+ <task_management>
26
+ Use the manage_todo_list tool for complex tasks to prevent forgetting steps.
27
+
28
+ WHEN TO USE TODO LISTS:
29
+ - Tasks with 3+ distinct steps
30
+ - Multi-file operations
31
+ - Complex workflows requiring planning
32
+ - Any task where tracking progress helps
33
+
34
+ TODO LIST RULES:
35
+ - Create todos BEFORE starting complex work
36
+ - Exactly ONE task must be in_progress at any time
37
+ - Mark tasks completed IMMEDIATELY after finishing
38
+ - Update status as you work through the list
39
+
40
+ <good_example>
41
+ User: Create a data pipeline that reads CSV, processes it, and generates report
42
+ Assistant: I'll use the todo list to track this multi-step task.
43
+ [Calls manage_todo_list with operation="add" for each step]
44
+ [Marks first task as in_progress before starting]
45
+ [Uses read_file tool]
46
+ [Marks as completed, moves to next task]
47
+ </good_example>
48
+
49
+ <bad_example>
50
+ User: Create a data pipeline that reads CSV, processes it, and generates report
51
+ Assistant: [Immediately starts without planning, forgets steps halfway through]
52
+ </bad_example>
53
+ </task_management>
54
+
55
+ <tool_usage_guidelines>
56
+ For file operations:
57
+ - Use glob_files to find files by pattern (fast, efficient)
58
+ - Use code_navigator to find function/class definitions (10x faster than grep, AST-based)
59
+ - Use grep_content for text search only (not for finding code structure)
60
+ - Use read_file only when you need full contents (avoid reading multiple large files at once)
61
+ - Use smart_edit for code edits (fuzzy match, auto backup, diff preview)
62
+ - Use edit_file for simple append/insert operations only
63
+ - Use write_file only for creating new files or complete rewrites
64
+
65
+ CRITICAL: Never read multiple large files in a single iteration - this causes context overflow!
66
+ Instead: Use code_navigator or grep_content to find specific information, then read only what you need.
67
+
68
+ For complex tasks:
69
+ - Use manage_todo_list to track progress
70
+ - Break into smaller, manageable steps
71
+ - Mark tasks completed as you go
72
+ - Keep exactly ONE task in_progress at a time
73
+
74
+ <good_example>
75
+ Task: Find all Python files that import 'requests'
76
+ Approach:
77
+ 1. Use glob_files with pattern "**/*.py" to find Python files
78
+ 2. Use grep_content with pattern "^import requests|^from requests" to search
79
+ Result: Efficient, minimal tokens used
80
+ </good_example>
81
+
82
+ <bad_example>
83
+ Task: Find all Python files that import 'requests'
84
+ Approach:
85
+ 1. Use read_file on every Python file one by one
86
+ 2. Manually search through content
87
+ Result: Wasteful, uses 100x more tokens
88
+ </bad_example>
89
+ </tool_usage_guidelines>
90
+
91
+ <workflow>
92
+ For each user request, follow this ReAct pattern:
93
+ 1. THINK: Analyze what's needed, choose best tools
94
+ 2. ACT: Execute with appropriate tools
95
+ 3. OBSERVE: Check results and learn from them
96
+ 4. REPEAT or COMPLETE: Continue the loop or provide final answer
97
+
98
+ When you have enough information, provide your final answer directly without using more tools.
99
+ </workflow>
100
+
101
+ <complex_task_strategy>
102
+ For complex tasks, combine tools to achieve an explore-plan-execute workflow:
103
+
104
+ 1. **EXPLORE**: Gather context before acting
105
+ - Use explore_context for parallel information gathering (code structure, web research)
106
+
107
+ 2. **PLAN**: Structure your approach
108
+ - Use manage_todo_list to break down the task into trackable steps
109
+ - Identify dependencies between steps
110
+
111
+ 3. **EXECUTE**: Carry out the plan
112
+ - Use parallel_execute for multiple independent/semi-dependent tasks
113
+ - Use regular tools for simple sequential operations
114
+
115
+ When to use each approach:
116
+ - Simple task (1-2 steps) → Use tools directly
117
+ - Medium task (3-5 steps) → Use todo list + sequential execution
118
+ - Complex task (needs research) → Explore → Plan → Execute
119
+ - Parallel workload → parallel_execute
120
+ </complex_task_strategy>"""
121
+
122
+ async def run(self, task: str, verify: bool = True) -> str:
123
+ """Execute ReAct loop until task is complete.
124
+
125
+ Args:
126
+ task: The task to complete
127
+ verify: If True, use ralph loop (outer verification). If False, use
128
+ plain react loop (suitable for interactive multi-turn sessions).
129
+
130
+ Returns:
131
+ Final answer as a string
132
+ """
133
+ # Build system message with context (only if not already in memory)
134
+ # This allows multi-turn conversations to reuse the same system message
135
+ if not self.memory.system_messages:
136
+ system_content = self.SYSTEM_PROMPT
137
+ try:
138
+ context = await format_context_prompt()
139
+ system_content = context + "\n" + system_content
140
+ except Exception:
141
+ # If context gathering fails, continue without it
142
+ pass
143
+
144
+ # Add system message only on first turn
145
+ await self.memory.add_message(LLMMessage(role="system", content=system_content))
146
+
147
+ # Add user task/message
148
+ await self.memory.add_message(LLMMessage(role="user", content=task))
149
+
150
+ tools = self.tool_executor.get_tool_schemas()
151
+
152
+ if verify:
153
+ # Use ralph loop (outer verification wrapping the inner ReAct loop)
154
+ result = await self._ralph_loop(
155
+ messages=[], # Not used when use_memory=True
156
+ tools=tools,
157
+ use_memory=True,
158
+ save_to_memory=True,
159
+ task=task,
160
+ max_iterations=Config.RALPH_LOOP_MAX_ITERATIONS,
161
+ )
162
+ else:
163
+ # Plain react loop without verification
164
+ result = await self._react_loop(
165
+ messages=[],
166
+ tools=tools,
167
+ use_memory=True,
168
+ save_to_memory=True,
169
+ task=task,
170
+ )
171
+
172
+ self._print_memory_stats()
173
+
174
+ # Save memory state to database after task completion
175
+ await self.memory.save_memory()
176
+
177
+ return result
178
+
179
+ def _print_memory_stats(self):
180
+ """Print memory usage statistics."""
181
+ stats = self.memory.get_stats()
182
+ terminal_ui.print_memory_stats(stats)