aloop 0.1.1__py3-none-any.whl

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.
Files changed (66) hide show
  1. agent/__init__.py +0 -0
  2. agent/agent.py +182 -0
  3. agent/base.py +406 -0
  4. agent/context.py +126 -0
  5. agent/prompts/__init__.py +1 -0
  6. agent/todo.py +149 -0
  7. agent/tool_executor.py +54 -0
  8. agent/verification.py +135 -0
  9. aloop-0.1.1.dist-info/METADATA +252 -0
  10. aloop-0.1.1.dist-info/RECORD +66 -0
  11. aloop-0.1.1.dist-info/WHEEL +5 -0
  12. aloop-0.1.1.dist-info/entry_points.txt +2 -0
  13. aloop-0.1.1.dist-info/licenses/LICENSE +21 -0
  14. aloop-0.1.1.dist-info/top_level.txt +9 -0
  15. cli.py +19 -0
  16. config.py +146 -0
  17. interactive.py +865 -0
  18. llm/__init__.py +51 -0
  19. llm/base.py +26 -0
  20. llm/compat.py +226 -0
  21. llm/content_utils.py +309 -0
  22. llm/litellm_adapter.py +450 -0
  23. llm/message_types.py +245 -0
  24. llm/model_manager.py +265 -0
  25. llm/retry.py +95 -0
  26. main.py +246 -0
  27. memory/__init__.py +20 -0
  28. memory/compressor.py +554 -0
  29. memory/manager.py +538 -0
  30. memory/serialization.py +82 -0
  31. memory/short_term.py +88 -0
  32. memory/store/__init__.py +6 -0
  33. memory/store/memory_store.py +100 -0
  34. memory/store/yaml_file_memory_store.py +414 -0
  35. memory/token_tracker.py +203 -0
  36. memory/types.py +51 -0
  37. tools/__init__.py +6 -0
  38. tools/advanced_file_ops.py +557 -0
  39. tools/base.py +51 -0
  40. tools/calculator.py +50 -0
  41. tools/code_navigator.py +975 -0
  42. tools/explore.py +254 -0
  43. tools/file_ops.py +150 -0
  44. tools/git_tools.py +791 -0
  45. tools/notify.py +69 -0
  46. tools/parallel_execute.py +420 -0
  47. tools/session_manager.py +205 -0
  48. tools/shell.py +147 -0
  49. tools/shell_background.py +470 -0
  50. tools/smart_edit.py +491 -0
  51. tools/todo.py +130 -0
  52. tools/web_fetch.py +673 -0
  53. tools/web_search.py +61 -0
  54. utils/__init__.py +15 -0
  55. utils/logger.py +105 -0
  56. utils/model_pricing.py +49 -0
  57. utils/runtime.py +75 -0
  58. utils/terminal_ui.py +422 -0
  59. utils/tui/__init__.py +39 -0
  60. utils/tui/command_registry.py +49 -0
  61. utils/tui/components.py +306 -0
  62. utils/tui/input_handler.py +393 -0
  63. utils/tui/model_ui.py +204 -0
  64. utils/tui/progress.py +292 -0
  65. utils/tui/status_bar.py +178 -0
  66. utils/tui/theme.py +165 -0
@@ -0,0 +1,252 @@
1
+ Metadata-Version: 2.4
2
+ Name: aloop
3
+ Version: 0.1.1
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+.
67
+
68
+ ```bash
69
+ pip install aloop
70
+ ```
71
+
72
+ Or install from source (for development):
73
+
74
+ ```bash
75
+ git clone https://github.com/luohaha/aloop.git
76
+ cd aloop
77
+ ./scripts/bootstrap.sh # requires uv
78
+ ```
79
+
80
+ ## Quick Start
81
+
82
+ ### 1. Configure Models
83
+
84
+ On first run, `~/.aloop/models.yaml` is created with a template. Edit it to add your provider and API key:
85
+
86
+ ```yaml
87
+ models:
88
+ openai/gpt-4o:
89
+ api_key: sk-...
90
+
91
+ anthropic/claude-3-5-sonnet-20241022:
92
+ api_key: sk-ant-...
93
+
94
+ ollama/llama2:
95
+ api_base: http://localhost:11434
96
+
97
+ default: openai/gpt-4o
98
+ ```
99
+
100
+ See [LiteLLM Providers](https://docs.litellm.ai/docs/providers) for the full list.
101
+
102
+ ### 2. Run
103
+
104
+ ```bash
105
+ # Interactive mode
106
+ aloop
107
+
108
+ # Single task (returns raw result)
109
+ aloop --task "Calculate 123 * 456"
110
+
111
+ # Resume last session
112
+ aloop --resume
113
+
114
+ # Resume specific session (ID prefix)
115
+ aloop --resume a1b2c3d4
116
+ ```
117
+
118
+ ## CLI Reference
119
+
120
+ | Flag | Short | Description |
121
+ |------|-------|-------------|
122
+ | `--task TEXT` | `-t` | Run a single task and exit |
123
+ | `--model ID` | `-m` | LiteLLM model ID to use |
124
+ | `--resume [ID]` | `-r` | Resume a session (`latest` if no ID given) |
125
+ | `--verbose` | `-v` | Enable verbose logging to `~/.aloop/logs/` |
126
+
127
+ ## Interactive Commands
128
+
129
+ ### Slash Commands
130
+
131
+ | Command | Description |
132
+ |---------|-------------|
133
+ | `/help` | Show help |
134
+ | `/clear` | Clear conversation and start fresh |
135
+ | `/stats` | Show memory and token usage statistics |
136
+ | `/resume [id]` | List or resume a previous session |
137
+ | `/model` | Pick a model (arrow keys + Enter) |
138
+ | `/model edit` | Open `~/.aloop/models.yaml` in editor (auto-reload on save) |
139
+ | `/theme` | Toggle dark/light theme |
140
+ | `/verbose` | Toggle thinking display |
141
+ | `/compact` | Toggle compact output |
142
+ | `/exit` | Exit (also `/quit`) |
143
+
144
+ ### Keyboard Shortcuts
145
+
146
+ | Key | Action |
147
+ |-----|--------|
148
+ | `/` | Command autocomplete |
149
+ | `Ctrl+C` | Cancel current operation |
150
+ | `Ctrl+L` | Clear screen |
151
+ | `Ctrl+T` | Toggle thinking display |
152
+ | `Ctrl+S` | Show quick stats |
153
+ | Up/Down | Navigate command history |
154
+
155
+ ## How It Works
156
+
157
+ **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.
158
+
159
+ **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).
160
+
161
+ **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`.
162
+
163
+ **Session persistence**: Conversations are saved as YAML files under `~/.aloop/sessions/`. Resume with `--resume` or `/resume`.
164
+
165
+ ## Tools
166
+
167
+ | Tool | Description |
168
+ |------|-------------|
169
+ | `read_file` | Read file contents |
170
+ | `write_file` | Write content to a file |
171
+ | `search_files` | Search for files by name |
172
+ | `edit_file` | Exact string replacement in files |
173
+ | `smart_edit` | LLM-assisted file editing |
174
+ | `glob_files` | Glob pattern file matching |
175
+ | `grep_content` | Regex search in file contents |
176
+ | `code_navigator` | AST-based code navigation (tree-sitter) |
177
+ | `calculate` | Evaluate expressions / run Python code |
178
+ | `shell` | Execute shell commands |
179
+ | `shell_task_status` | Check background shell task status |
180
+ | `web_search` | Web search (DuckDuckGo) |
181
+ | `web_fetch` | Fetch and extract web page content |
182
+ | `explore_context` | Explore project structure and context |
183
+ | `parallel_execute` | Run multiple tool calls in parallel |
184
+ | `notify` | Send email notifications (Resend) |
185
+ | `manage_todo_list` | Manage a task/todo list |
186
+
187
+ ## Project Structure
188
+
189
+ ```
190
+ aloop/
191
+ ├── main.py # Entry point (argparse)
192
+ ├── cli.py # CLI wrapper (`aloop` entry point)
193
+ ├── interactive.py # Interactive session, model setup, TUI
194
+ ├── config.py # Runtime config (~/.aloop/config)
195
+ ├── agent/
196
+ │ ├── base.py # BaseAgent (ReAct + Ralph loops)
197
+ │ ├── agent.py # LoopAgent
198
+ │ ├── verification.py # LLMVerifier for Ralph loop
199
+ │ ├── context.py # Context injection (cwd, platform, date)
200
+ │ ├── tool_executor.py # Tool execution engine
201
+ │ └── todo.py # Todo list data structure
202
+ ├── llm/
203
+ │ ├── litellm_adapter.py # LiteLLM adapter (100+ providers)
204
+ │ ├── model_manager.py # Model config from ~/.aloop/models.yaml
205
+ │ ├── retry.py # Retry with exponential backoff
206
+ │ └── message_types.py # LLMMessage, LLMResponse, ToolCall
207
+ ├── memory/
208
+ │ ├── manager.py # Memory orchestrator + persistence
209
+ │ ├── compressor.py # LLM-driven compression
210
+ │ ├── short_term.py # Short-term memory (sliding window)
211
+ │ ├── token_tracker.py # Token counting + cost tracking
212
+ │ ├── types.py # Core data structures
213
+ │ └── store/
214
+ │ └── yaml_file_memory_store.py # YAML session persistence
215
+ ├── tools/ # 18 tool implementations
216
+ ├── utils/
217
+ │ ├── tui/ # TUI components (input, themes, status bar)
218
+ │ ├── logger.py # Logging setup
219
+ │ └── model_pricing.py # Model pricing data
220
+ ├── docs/ # Documentation
221
+ ├── test/ # Tests
222
+ ├── scripts/ # Dev scripts (bootstrap.sh, dev.sh)
223
+ └── rfc/ # RFC design documents
224
+ ```
225
+
226
+ ## Configuration
227
+
228
+ Runtime settings live in `~/.aloop/config` (auto-created). Key settings:
229
+
230
+ | Setting | Default | Description |
231
+ |---------|---------|-------------|
232
+ | `MAX_ITERATIONS` | `1000` | Maximum agent loop iterations |
233
+ | `TOOL_TIMEOUT` | `600` | Tool execution timeout (seconds) |
234
+ | `RALPH_LOOP_MAX_ITERATIONS` | `3` | Max verification attempts |
235
+ | `MEMORY_ENABLED` | `true` | Enable memory management |
236
+ | `MEMORY_COMPRESSION_THRESHOLD` | `60000` | Token threshold for compression |
237
+ | `MEMORY_SHORT_TERM_SIZE` | `100` | Messages kept at full fidelity |
238
+ | `RETRY_MAX_ATTEMPTS` | `3` | Rate-limit retry attempts |
239
+
240
+ See [Configuration Guide](docs/configuration.md) for all settings.
241
+
242
+ ## Documentation
243
+
244
+ - [Configuration](docs/configuration.md) -- model setup, runtime settings, custom endpoints
245
+ - [Examples](docs/examples.md) -- usage patterns and programmatic API
246
+ - [Memory Management](docs/memory-management.md) -- compression, persistence, token tracking
247
+ - [Extending](docs/extending.md) -- adding tools, agents, LLM providers
248
+ - [Packaging](docs/packaging.md) -- building, publishing, Docker
249
+
250
+ ## License
251
+
252
+ MIT License
@@ -0,0 +1,66 @@
1
+ cli.py,sha256=j3B6la8ArJ5BAvR_vCw-_oDp8wyX9D25mKRJN96b8U8,338
2
+ config.py,sha256=1D2VjNtZidj4NuA2AN013djKVFqxstc53zUd-Ppz2U4,4980
3
+ interactive.py,sha256=TSoBsVuxsX_RxGFKRmqHEnQL7KOVL7s_GnCF7E3t6xc,34369
4
+ main.py,sha256=P_96WocjwBkcBVj0zGy2r-S9FZbu8qpFXOdAvIaXkio,7710
5
+ agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ agent/agent.py,sha256=VfSQYKnLHiKU3mXJ9Ri8sHwYJpI7Ug14GgH3XqhoNO0,6597
7
+ agent/base.py,sha256=WerzJeHo0zqw7Gllenf3cp3c2fqjzfu027p9js5jy1Q,15643
8
+ agent/context.py,sha256=paxoP5KRqNMnEEREa9Mj8QVIdpgtpj9FafwtvuTe1I8,3793
9
+ agent/todo.py,sha256=dM6DSCeV9QbatDVx1HEUK46b_XEdcPCf_1uYYZN4Fsg,5272
10
+ agent/tool_executor.py,sha256=uvxwhiqQh4MkSZAhHbcUkFHRpuiM7XfMQOh_WCFMI_c,1951
11
+ agent/verification.py,sha256=kFOLUJfd2iK5P_OIctacRNdGhwzNXTd_cdcXdv1xGqQ,4268
12
+ agent/prompts/__init__.py,sha256=bnOLBsNS6jXAS6hQirULAoJ6gs1tC2suZ501i4KRRzA,36
13
+ aloop-0.1.1.dist-info/licenses/LICENSE,sha256=QWrc--GLlkEskZCiT0qjbtLKXYA5It4gp345uIltMew,1066
14
+ llm/__init__.py,sha256=GhTKAf36pjBV6fuijXTCBcLk4XqmUYeCbrZATvb_mW8,1149
15
+ llm/base.py,sha256=mESX6l3dbZPfh9-l9txVvvVJWpgvNIchm3tD5MkAFn8,551
16
+ llm/compat.py,sha256=tl5De-u86VuWLbeTmPrBVRosBtyPu3kM504fAwARFeI,6396
17
+ llm/content_utils.py,sha256=tcwNRlMRpFEVeCsjyCcGrcy1WxtqLiK1kRXZw0_IL4U,8262
18
+ llm/litellm_adapter.py,sha256=Zm4OSNC4oacLunf1Bkjkdnwwe4F9n0GNUeXbFcQeCFA,16934
19
+ llm/message_types.py,sha256=sjcjsJGy1JtWMtjfqrrgpyVWntg6z47unxAHVID3QIQ,7117
20
+ llm/model_manager.py,sha256=ms5MNAjlRWWV5RYbq60Qb0BbWrYfjpMkgphMu82RNJA,8704
21
+ llm/retry.py,sha256=0ouN1yAD2mCNbtFbrTxAwWXiQAW7p1XIUei623WcUpw,2710
22
+ memory/__init__.py,sha256=7iLqzMIysHkC_wqftqSPPFVF6peHlX_agtRTveWhHu4,578
23
+ memory/compressor.py,sha256=edV7B61CipvgQq5LGGdOwOsoRiuHL2fz_sC-MnSyKSM,23238
24
+ memory/manager.py,sha256=m0r3b47KXMj8ymAZeQwZ6pEFlRqHyqVdu4OlLQ-D4xc,19474
25
+ memory/serialization.py,sha256=whX7E2n2UyamD1iOtQS2PkKhbb-ebwwnvfu-fh-Y2tE,2194
26
+ memory/short_term.py,sha256=RHPvHxqAzSJq_FeepL5qk0v-zOYnTIKP6l_jtJ0jB7c,2519
27
+ memory/token_tracker.py,sha256=xufZ-FWjcGkTdkK5jmns3CTIqklv6ctFCmKH5yl9uiY,6953
28
+ memory/types.py,sha256=GLOLB0f0IN3cb7Bv-guVwtR17mJG7zlvJjRWtXlzyao,1744
29
+ memory/store/__init__.py,sha256=23CgsW2M-exOH0pt3XEFvtNP1CQ15AgyMVo9rMHKGsc,205
30
+ memory/store/memory_store.py,sha256=_R27AitWIP6GUIGN5x9QsjL6qKs2eWKfyVps8m3ekFw,2733
31
+ memory/store/yaml_file_memory_store.py,sha256=5At2tba8Ccch97h58hiIH0L5yqhiqctuQD_OXxq8Z8U,14447
32
+ tools/__init__.py,sha256=iAVcW_A4I2aVuiI3PoVMcCBe8cFGqe6TIBuaZ_cGD-Q,190
33
+ tools/advanced_file_ops.py,sha256=dZlgOvAVOhVRIyOgwU6tlaSNituQoEivKxiHQo9DNME,19938
34
+ tools/base.py,sha256=OtDzJg4c-CKtHTohPVaNDD_8x1xPKqCXE8SGJd8Xr_c,1397
35
+ tools/calculator.py,sha256=Sl201BysnFa-7tduxKstnOT94syAHyle2rTgztXA6Ho,1500
36
+ tools/code_navigator.py,sha256=Unj9mjbsTOJQNgVi980zrgeg1Msp3rHzqo-am8eqwEI,38336
37
+ tools/explore.py,sha256=hR2_TMjVYCrqrj9JFSmTgIiXyvlE7_vFYtrlxLtVGG4,8171
38
+ tools/file_ops.py,sha256=43qs42oIbCd9q7UD1scEKUAbKdRuzjukTjxw_ziJmuE,5082
39
+ tools/git_tools.py,sha256=a0pLYnk4OjXB7ak3jmlQLIDet9Bf_rolNGsGHS7XgqA,23521
40
+ tools/notify.py,sha256=gWlTx-9SSQ2bsITVkJPCUgX6Mm9ve2TtfgMHq4RksKM,2103
41
+ tools/parallel_execute.py,sha256=AD_VwCchLOkHLYYliJn0dGupX4wB01X1RmV0Lz3DqXM,13197
42
+ tools/session_manager.py,sha256=aXdRYWR9-NH5K-E1NfmjxG0txR5fvmhAX-mFjmq9N7c,6484
43
+ tools/shell.py,sha256=Ozn4ldWA4DzIkNHt1HjXD_F0A300Zdnj7IYYlrGqIqo,5492
44
+ tools/shell_background.py,sha256=aAduugXVEzs2IXFmXq62cHryZDKknKsmdxbI_0KgQK4,16070
45
+ tools/smart_edit.py,sha256=GU3SYMnpr7DCXNVL8HqphwoajRERF1vQT_e1LXmcohw,17804
46
+ tools/todo.py,sha256=nm3lKm-lE6ta0Q3g13XKLQ7L3JLATX4VuoZtUu9KvCU,4412
47
+ tools/web_fetch.py,sha256=wW6zk0uA6nMuH5ecs2ExgdPJv9-tn3xP1H92-tc5ni4,24827
48
+ tools/web_search.py,sha256=7D_86Jk8sQCOPCiMa_NtFXTpduZiXlwr7IRyREBRbIg,2025
49
+ utils/__init__.py,sha256=WKSnJ2XGVq5199-gTkIO0Acd4RT9LZofDQeOkbzVq-c,424
50
+ utils/logger.py,sha256=-8UiH5F5jm3IGbJvlcNhvkF_t8fUSKmuqnZPsLVSb8M,3072
51
+ utils/model_pricing.py,sha256=r5LVdkQNqYMm8_W7Kb2iXu9oHHHz7zHjHYyEqOb3wRA,2311
52
+ utils/runtime.py,sha256=tGl__Ss2SSEWsyMxEhklKPm2HrbbKRTzgtk7Tq5lCxU,1740
53
+ utils/terminal_ui.py,sha256=kOfT9O2UdZCOcwfx0TZ6MziOgGEhC1C_eB6bjv0sH_0,12302
54
+ utils/tui/__init__.py,sha256=bN2Iof8dzqp_zT7KRS9vFGWEb5pGsl36OQ9EtxmiOVw,915
55
+ utils/tui/command_registry.py,sha256=EYsZssHLYDaoaVyc_t1MEWOiaD5RjyEGZS8jflEquIQ,1597
56
+ utils/tui/components.py,sha256=m5FLAEfI-eO3773ug9qmTw5AXrjBtKIFyrCAb7Mibl4,9492
57
+ utils/tui/input_handler.py,sha256=e2PtQRWG-VfRyq8VuhsaOFkE7dE0b8o3EUt5YPbsl-M,14022
58
+ utils/tui/model_ui.py,sha256=Oqc-2NKGiyg-4fZNgnxO0drwrHVKrjK9EzTCwd4oXG4,6234
59
+ utils/tui/progress.py,sha256=Yb0bn6XSBvluLSJqgkvHt_SMXDob5LwT-OwR1b7aMDE,8082
60
+ utils/tui/status_bar.py,sha256=AG_zb9qGkkNGLMHdYgWBvnK8JVppmUVKjOmj-qCVLg4,5333
61
+ utils/tui/theme.py,sha256=x0wnQw21Ufy1cm5DGMQroJ88J_rYBcezVHlwg4-mdwY,5606
62
+ aloop-0.1.1.dist-info/METADATA,sha256=H3HAsDatOc5D7BiqSLTfWgBDZnHBtjvOLzTAfNGXHLQ,9232
63
+ aloop-0.1.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
64
+ aloop-0.1.1.dist-info/entry_points.txt,sha256=fXfq7fpc79S3RQ7TzXSSyiA2L6yedfo-3o1PXEFXs0I,35
65
+ aloop-0.1.1.dist-info/top_level.txt,sha256=RcMBYcKEUojok3GYEagBOce8M7DyEAelgCypkcTrSE0,57
66
+ aloop-0.1.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ aloop = cli:main
@@ -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,9 @@
1
+ agent
2
+ cli
3
+ config
4
+ interactive
5
+ llm
6
+ main
7
+ memory
8
+ tools
9
+ utils
cli.py ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env python3
2
+ """Command-line interface for aloop."""
3
+
4
+ import os
5
+ import sys
6
+
7
+ # Add current directory to path to allow imports
8
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
9
+
10
+
11
+ def main():
12
+ """Main CLI entry point."""
13
+ from main import main as run_main
14
+
15
+ run_main()
16
+
17
+
18
+ if __name__ == "__main__":
19
+ main()
config.py ADDED
@@ -0,0 +1,146 @@
1
+ """Configuration management for the agentic system."""
2
+
3
+ import os
4
+ import random
5
+
6
+ # Define path constants directly to avoid circular imports with utils
7
+ # (utils.terminal_ui imports Config, and utils.runtime is in the utils package)
8
+ _RUNTIME_DIR = os.path.join(os.path.expanduser("~"), ".aloop")
9
+ _CONFIG_FILE = os.path.join(_RUNTIME_DIR, "config")
10
+
11
+ # Default configuration template
12
+ _DEFAULT_CONFIG = """\
13
+ # aloop Configuration
14
+ #
15
+ # NOTE: Model configuration lives in `~/.aloop/models.yaml`.
16
+ # This file controls non-model runtime settings only.
17
+
18
+ TOOL_TIMEOUT=600
19
+ MAX_ITERATIONS=1000
20
+
21
+ # Ralph Loop (outer verification loop — re-checks task completion)
22
+ # RALPH_LOOP_MAX_ITERATIONS=3
23
+ """
24
+
25
+
26
+ def _load_config(path: str) -> dict[str, str]:
27
+ """Parse a KEY=VALUE config file, skipping comments and blank lines."""
28
+ cfg: dict[str, str] = {}
29
+ if not os.path.isfile(path):
30
+ return cfg
31
+ with open(path, encoding="utf-8") as f:
32
+ for line in f:
33
+ line = line.strip()
34
+ if not line or line.startswith("#"):
35
+ continue
36
+ if "=" not in line:
37
+ continue
38
+ key, _, value = line.partition("=")
39
+ # Strip inline comments (# ...) from the value
40
+ if "#" in value:
41
+ value = value[: value.index("#")]
42
+ cfg[key.strip()] = value.strip()
43
+ return cfg
44
+
45
+
46
+ def _ensure_config():
47
+ """Ensure ~/.aloop/config exists, create with defaults if not."""
48
+ if not os.path.exists(_CONFIG_FILE):
49
+ os.makedirs(_RUNTIME_DIR, exist_ok=True)
50
+ with open(_CONFIG_FILE, "w", encoding="utf-8") as f:
51
+ f.write(_DEFAULT_CONFIG)
52
+
53
+
54
+ # Ensure config exists and load it
55
+ _ensure_config()
56
+ _cfg = _load_config(_CONFIG_FILE)
57
+
58
+
59
+ def get_raw_config() -> dict[str, str]:
60
+ """Get the raw config dictionary.
61
+
62
+ Returns:
63
+ Dictionary of config key-value pairs
64
+ """
65
+ return _cfg.copy()
66
+
67
+
68
+ class Config:
69
+ """Configuration for the agentic system.
70
+
71
+ All configuration is centralized here. Access config values directly via Config.XXX.
72
+ """
73
+
74
+ # Model configuration is handled by `~/.aloop/models.yaml` via ModelManager.
75
+ # `~/.aloop/config` controls non-model runtime settings only.
76
+ TOOL_TIMEOUT = float(_cfg.get("TOOL_TIMEOUT", "600"))
77
+
78
+ # Agent Configuration
79
+ MAX_ITERATIONS = int(_cfg.get("MAX_ITERATIONS", "1000"))
80
+
81
+ # Ralph Loop (outer verification loop)
82
+ RALPH_LOOP_MAX_ITERATIONS = int(_cfg.get("RALPH_LOOP_MAX_ITERATIONS", "3"))
83
+
84
+ # Retry Configuration
85
+ RETRY_MAX_ATTEMPTS = int(_cfg.get("RETRY_MAX_ATTEMPTS", "3"))
86
+ RETRY_INITIAL_DELAY = float(_cfg.get("RETRY_INITIAL_DELAY", "1.0"))
87
+ RETRY_MAX_DELAY = float(_cfg.get("RETRY_MAX_DELAY", "60.0"))
88
+ RETRY_EXPONENTIAL_BASE = 2.0
89
+ RETRY_JITTER = True
90
+
91
+ # Memory Management Configuration
92
+ MEMORY_ENABLED = _cfg.get("MEMORY_ENABLED", "true").lower() == "true"
93
+ MEMORY_COMPRESSION_THRESHOLD = int(_cfg.get("MEMORY_COMPRESSION_THRESHOLD", "60000"))
94
+ MEMORY_SHORT_TERM_SIZE = int(_cfg.get("MEMORY_SHORT_TERM_SIZE", "100"))
95
+ MEMORY_SHORT_TERM_MIN_SIZE = int(_cfg.get("MEMORY_SHORT_TERM_MIN_SIZE", "6"))
96
+ MEMORY_COMPRESSION_RATIO = float(_cfg.get("MEMORY_COMPRESSION_RATIO", "0.3"))
97
+ MEMORY_PRESERVE_SYSTEM_PROMPTS = True
98
+
99
+ # Logging Configuration
100
+ # Note: Logging is now controlled via --verbose flag
101
+ # LOG_DIR is now ~/.aloop/logs/ (see utils.runtime)
102
+ LOG_LEVEL = _cfg.get("LOG_LEVEL", "DEBUG").upper()
103
+
104
+ # TUI Configuration
105
+ TUI_THEME = _cfg.get("TUI_THEME", "dark") # "dark" or "light"
106
+ TUI_SHOW_THINKING = _cfg.get("TUI_SHOW_THINKING", "true").lower() == "true"
107
+ TUI_THINKING_MAX_PREVIEW = int(_cfg.get("TUI_THINKING_MAX_PREVIEW", "300"))
108
+ TUI_STATUS_BAR = _cfg.get("TUI_STATUS_BAR", "true").lower() == "true"
109
+ TUI_COMPACT_MODE = _cfg.get("TUI_COMPACT_MODE", "false").lower() == "true"
110
+
111
+ # Email Notification Configuration (Resend)
112
+ RESEND_API_KEY = _cfg.get("RESEND_API_KEY") or ""
113
+ NOTIFY_EMAIL_FROM = _cfg.get("NOTIFY_EMAIL_FROM") or ""
114
+
115
+ @classmethod
116
+ def get_retry_delay(cls, attempt: int) -> float:
117
+ """Calculate delay for a given retry attempt using exponential backoff.
118
+
119
+ Args:
120
+ attempt: Current attempt number (0-indexed)
121
+
122
+ Returns:
123
+ Delay in seconds
124
+ """
125
+ # Calculate exponential backoff
126
+ delay = min(
127
+ cls.RETRY_INITIAL_DELAY * (cls.RETRY_EXPONENTIAL_BASE**attempt),
128
+ cls.RETRY_MAX_DELAY,
129
+ )
130
+
131
+ # Add jitter to avoid thundering herd
132
+ if cls.RETRY_JITTER:
133
+ delay = delay * (0.5 + random.random())
134
+
135
+ return delay
136
+
137
+ @classmethod
138
+ def validate(cls):
139
+ """Validate required configuration.
140
+
141
+ Raises:
142
+ ValueError: If required configuration is missing
143
+ """
144
+ # Model configuration is handled by `~/.aloop/models.yaml` via ModelManager.
145
+ # `~/.aloop/config` is used for non-model runtime settings only.
146
+ return