nixclaw 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.
- nixclaw-0.1.0/LICENSE +21 -0
- nixclaw-0.1.0/PKG-INFO +195 -0
- nixclaw-0.1.0/README.md +149 -0
- nixclaw-0.1.0/nixclaw/__init__.py +40 -0
- nixclaw-0.1.0/nixclaw/__main__.py +4 -0
- nixclaw-0.1.0/nixclaw/agents/__init__.py +0 -0
- nixclaw-0.1.0/nixclaw/agents/agent_factory.py +157 -0
- nixclaw-0.1.0/nixclaw/agents/agent_profiles.py +127 -0
- nixclaw-0.1.0/nixclaw/agents/base_agent.py +111 -0
- nixclaw-0.1.0/nixclaw/agents/orchestrator.py +198 -0
- nixclaw-0.1.0/nixclaw/api/__init__.py +0 -0
- nixclaw-0.1.0/nixclaw/api/app.py +31 -0
- nixclaw-0.1.0/nixclaw/api/routes.py +94 -0
- nixclaw-0.1.0/nixclaw/api/schemas.py +37 -0
- nixclaw-0.1.0/nixclaw/config.py +108 -0
- nixclaw-0.1.0/nixclaw/core/__init__.py +0 -0
- nixclaw-0.1.0/nixclaw/core/async_task_queue.py +223 -0
- nixclaw-0.1.0/nixclaw/core/command_executor.py +129 -0
- nixclaw-0.1.0/nixclaw/core/context_manager.py +84 -0
- nixclaw-0.1.0/nixclaw/core/event_bus.py +80 -0
- nixclaw-0.1.0/nixclaw/core/health.py +89 -0
- nixclaw-0.1.0/nixclaw/core/retry.py +81 -0
- nixclaw-0.1.0/nixclaw/core/security.py +52 -0
- nixclaw-0.1.0/nixclaw/core/task_manager.py +176 -0
- nixclaw-0.1.0/nixclaw/integrations/__init__.py +0 -0
- nixclaw-0.1.0/nixclaw/integrations/openai_client.py +37 -0
- nixclaw-0.1.0/nixclaw/integrations/telegram_bot.py +295 -0
- nixclaw-0.1.0/nixclaw/integrations/telegram_log.py +203 -0
- nixclaw-0.1.0/nixclaw/integrations/webhooks.py +59 -0
- nixclaw-0.1.0/nixclaw/logger.py +62 -0
- nixclaw-0.1.0/nixclaw/main.py +175 -0
- nixclaw-0.1.0/nixclaw/storage/__init__.py +0 -0
- nixclaw-0.1.0/nixclaw/storage/cache.py +14 -0
- nixclaw-0.1.0/nixclaw/storage/database.py +135 -0
- nixclaw-0.1.0/nixclaw/storage/models.py +132 -0
- nixclaw-0.1.0/nixclaw/storage/repository.py +207 -0
- nixclaw-0.1.0/nixclaw/tools/__init__.py +0 -0
- nixclaw-0.1.0/nixclaw/tools/agent_tool.py +35 -0
- nixclaw-0.1.0/nixclaw/tools/directory_ops.py +62 -0
- nixclaw-0.1.0/nixclaw/tools/file_operations.py +67 -0
- nixclaw-0.1.0/nixclaw/tools/search_tools.py +111 -0
- nixclaw-0.1.0/nixclaw/tools/shell_executor.py +209 -0
- nixclaw-0.1.0/nixclaw/tools/telegram_tool.py +44 -0
- nixclaw-0.1.0/nixclaw.egg-info/PKG-INFO +195 -0
- nixclaw-0.1.0/nixclaw.egg-info/SOURCES.txt +49 -0
- nixclaw-0.1.0/nixclaw.egg-info/dependency_links.txt +1 -0
- nixclaw-0.1.0/nixclaw.egg-info/entry_points.txt +2 -0
- nixclaw-0.1.0/nixclaw.egg-info/requires.txt +28 -0
- nixclaw-0.1.0/nixclaw.egg-info/top_level.txt +1 -0
- nixclaw-0.1.0/pyproject.toml +63 -0
- nixclaw-0.1.0/setup.cfg +4 -0
nixclaw-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NixClaw
|
|
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.
|
nixclaw-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nixclaw
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Multi-agent AI system built on AutoGen for autonomous task execution
|
|
5
|
+
Author: NixClaw
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/nixclaw/nixclaw
|
|
8
|
+
Project-URL: Repository, https://github.com/nixclaw/nixclaw
|
|
9
|
+
Keywords: ai,agents,multi-agent,autogen,automation,orchestration,llm
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: autogen-agentchat==0.7.5
|
|
23
|
+
Requires-Dist: autogen-core==0.7.5
|
|
24
|
+
Requires-Dist: autogen-ext[openai]==0.7.5
|
|
25
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
26
|
+
Requires-Dist: pydantic>=2.0.0
|
|
27
|
+
Requires-Dist: aiofiles>=24.0.0
|
|
28
|
+
Requires-Dist: requests>=2.31.0
|
|
29
|
+
Requires-Dist: sqlalchemy>=2.0.0
|
|
30
|
+
Requires-Dist: aiosqlite>=0.20.0
|
|
31
|
+
Provides-Extra: api
|
|
32
|
+
Requires-Dist: fastapi>=0.110.0; extra == "api"
|
|
33
|
+
Requires-Dist: uvicorn>=0.27.0; extra == "api"
|
|
34
|
+
Requires-Dist: httpx>=0.27.0; extra == "api"
|
|
35
|
+
Provides-Extra: telegram
|
|
36
|
+
Requires-Dist: python-telegram-bot>=21.0; extra == "telegram"
|
|
37
|
+
Provides-Extra: storage
|
|
38
|
+
Requires-Dist: redis>=5.0.0; extra == "storage"
|
|
39
|
+
Provides-Extra: all
|
|
40
|
+
Requires-Dist: nixclaw[api,storage,telegram]; extra == "all"
|
|
41
|
+
Provides-Extra: dev
|
|
42
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
43
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
44
|
+
Requires-Dist: ruff>=0.3.0; extra == "dev"
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
|
|
47
|
+
# NixClaw
|
|
48
|
+
|
|
49
|
+
Multi-agent AI system built on [AutoGen](https://github.com/microsoft/autogen) for autonomous task execution.
|
|
50
|
+
|
|
51
|
+
NixClaw breaks down complex tasks, dynamically creates specialized AI agents, and orchestrates them to deliver results — all with human-in-the-loop capabilities via Telegram.
|
|
52
|
+
|
|
53
|
+
## Installation
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install nixclaw
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
With optional extras:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install nixclaw[all] # Everything (API, Telegram, storage)
|
|
63
|
+
pip install nixclaw[api] # REST API (FastAPI)
|
|
64
|
+
pip install nixclaw[telegram] # Telegram bot integration
|
|
65
|
+
pip install nixclaw[storage] # Database persistence (SQLAlchemy)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Quick Start
|
|
69
|
+
|
|
70
|
+
### As a CLI tool
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# One-shot task
|
|
74
|
+
nixclaw "Analyze the project structure and list all Python files"
|
|
75
|
+
|
|
76
|
+
# Interactive mode
|
|
77
|
+
nixclaw --interactive
|
|
78
|
+
|
|
79
|
+
# Team mode with specific agent profiles
|
|
80
|
+
nixclaw --team CodeGenerator,Analyzer "Build a REST API for user management"
|
|
81
|
+
|
|
82
|
+
# Start REST API server
|
|
83
|
+
nixclaw --serve
|
|
84
|
+
|
|
85
|
+
# Start Telegram bot
|
|
86
|
+
nixclaw --telegram
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### As a Python library
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
import asyncio
|
|
93
|
+
from nixclaw import Orchestrator
|
|
94
|
+
|
|
95
|
+
async def main():
|
|
96
|
+
orchestrator = Orchestrator()
|
|
97
|
+
result = await orchestrator.run("Analyze the codebase and find potential bugs")
|
|
98
|
+
print(result)
|
|
99
|
+
await orchestrator.close()
|
|
100
|
+
|
|
101
|
+
asyncio.run(main())
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### Advanced: Direct agent control
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
import asyncio
|
|
108
|
+
from nixclaw import AgentFactory
|
|
109
|
+
|
|
110
|
+
async def main():
|
|
111
|
+
factory = AgentFactory.get_instance()
|
|
112
|
+
agent = await factory.create_agent("CodeGenerator")
|
|
113
|
+
result = await agent.run("Write a Python function to calculate fibonacci numbers")
|
|
114
|
+
print(agent.get_result_text(result))
|
|
115
|
+
await factory.cleanup_all()
|
|
116
|
+
|
|
117
|
+
asyncio.run(main())
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Configuration
|
|
121
|
+
|
|
122
|
+
Create a `.env` file in your project root:
|
|
123
|
+
|
|
124
|
+
```env
|
|
125
|
+
# LLM Configuration (required)
|
|
126
|
+
LLM_MODEL=gpt-4
|
|
127
|
+
LLM_API_KEY=your_api_key_here
|
|
128
|
+
LLM_BASE_URL=https://api.openai.com/v1
|
|
129
|
+
|
|
130
|
+
# Telegram Bot (optional)
|
|
131
|
+
TELEGRAM_BOT_TOKEN=your_bot_token
|
|
132
|
+
TELEGRAM_BOT_TOKEN_LOG=your_log_bot_token
|
|
133
|
+
TELEGRAM_USER_IDS=your_user_id
|
|
134
|
+
|
|
135
|
+
# Agent Settings
|
|
136
|
+
AGENT_MAX_CONCURRENT_AGENTS=10
|
|
137
|
+
AGENT_ENABLE_REFLECTION=true
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
See [.env.example](.env.example) for all available options.
|
|
141
|
+
|
|
142
|
+
## Agent Profiles
|
|
143
|
+
|
|
144
|
+
NixClaw includes 6 specialist agent profiles:
|
|
145
|
+
|
|
146
|
+
| Profile | Description |
|
|
147
|
+
|---------|-------------|
|
|
148
|
+
| **CodeGenerator** | Generates, modifies, and refactors code |
|
|
149
|
+
| **Analyzer** | Analyzes code, data, and systems for insights |
|
|
150
|
+
| **Researcher** | Gathers information and synthesizes findings |
|
|
151
|
+
| **SystemAdmin** | Executes system commands and manages infrastructure |
|
|
152
|
+
| **Debugger** | Investigates and fixes bugs systematically |
|
|
153
|
+
| **General** | General-purpose agent for miscellaneous tasks |
|
|
154
|
+
|
|
155
|
+
## REST API
|
|
156
|
+
|
|
157
|
+
Start the API server:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
nixclaw --serve --port 8000
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Endpoints:
|
|
164
|
+
|
|
165
|
+
| Method | Path | Description |
|
|
166
|
+
|--------|------|-------------|
|
|
167
|
+
| POST | `/api/v1/tasks` | Submit a task |
|
|
168
|
+
| GET | `/api/v1/tasks/{id}` | Get task status |
|
|
169
|
+
| GET | `/api/v1/tasks` | List all tasks |
|
|
170
|
+
| POST | `/api/v1/tasks/{id}/cancel` | Cancel a task |
|
|
171
|
+
| GET | `/api/v1/agents/status` | Agent overview |
|
|
172
|
+
| GET | `/api/v1/health` | Health check |
|
|
173
|
+
|
|
174
|
+
## Telegram Integration
|
|
175
|
+
|
|
176
|
+
NixClaw supports two Telegram bots:
|
|
177
|
+
|
|
178
|
+
- **Primary bot** (`TELEGRAM_BOT_TOKEN`): Receives commands (`/task`, `/status`, `/agents`) and sends task notifications
|
|
179
|
+
- **Log bot** (`TELEGRAM_BOT_TOKEN_LOG`): Mirrors all output from CLI, API, and Telegram to a dedicated log channel
|
|
180
|
+
|
|
181
|
+
## Architecture
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
nixclaw/
|
|
185
|
+
├── agents/ # Agent system (orchestrator, factory, profiles)
|
|
186
|
+
├── tools/ # Built-in tools (file ops, shell, search)
|
|
187
|
+
├── core/ # Task manager, context, event bus, retry, security
|
|
188
|
+
├── storage/ # Database persistence (SQLAlchemy + SQLite)
|
|
189
|
+
├── api/ # REST API (FastAPI)
|
|
190
|
+
└── integrations/ # Telegram, webhooks, LLM client
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## License
|
|
194
|
+
|
|
195
|
+
MIT
|
nixclaw-0.1.0/README.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# NixClaw
|
|
2
|
+
|
|
3
|
+
Multi-agent AI system built on [AutoGen](https://github.com/microsoft/autogen) for autonomous task execution.
|
|
4
|
+
|
|
5
|
+
NixClaw breaks down complex tasks, dynamically creates specialized AI agents, and orchestrates them to deliver results — all with human-in-the-loop capabilities via Telegram.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install nixclaw
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
With optional extras:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install nixclaw[all] # Everything (API, Telegram, storage)
|
|
17
|
+
pip install nixclaw[api] # REST API (FastAPI)
|
|
18
|
+
pip install nixclaw[telegram] # Telegram bot integration
|
|
19
|
+
pip install nixclaw[storage] # Database persistence (SQLAlchemy)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### As a CLI tool
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# One-shot task
|
|
28
|
+
nixclaw "Analyze the project structure and list all Python files"
|
|
29
|
+
|
|
30
|
+
# Interactive mode
|
|
31
|
+
nixclaw --interactive
|
|
32
|
+
|
|
33
|
+
# Team mode with specific agent profiles
|
|
34
|
+
nixclaw --team CodeGenerator,Analyzer "Build a REST API for user management"
|
|
35
|
+
|
|
36
|
+
# Start REST API server
|
|
37
|
+
nixclaw --serve
|
|
38
|
+
|
|
39
|
+
# Start Telegram bot
|
|
40
|
+
nixclaw --telegram
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### As a Python library
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
import asyncio
|
|
47
|
+
from nixclaw import Orchestrator
|
|
48
|
+
|
|
49
|
+
async def main():
|
|
50
|
+
orchestrator = Orchestrator()
|
|
51
|
+
result = await orchestrator.run("Analyze the codebase and find potential bugs")
|
|
52
|
+
print(result)
|
|
53
|
+
await orchestrator.close()
|
|
54
|
+
|
|
55
|
+
asyncio.run(main())
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### Advanced: Direct agent control
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
import asyncio
|
|
62
|
+
from nixclaw import AgentFactory
|
|
63
|
+
|
|
64
|
+
async def main():
|
|
65
|
+
factory = AgentFactory.get_instance()
|
|
66
|
+
agent = await factory.create_agent("CodeGenerator")
|
|
67
|
+
result = await agent.run("Write a Python function to calculate fibonacci numbers")
|
|
68
|
+
print(agent.get_result_text(result))
|
|
69
|
+
await factory.cleanup_all()
|
|
70
|
+
|
|
71
|
+
asyncio.run(main())
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Configuration
|
|
75
|
+
|
|
76
|
+
Create a `.env` file in your project root:
|
|
77
|
+
|
|
78
|
+
```env
|
|
79
|
+
# LLM Configuration (required)
|
|
80
|
+
LLM_MODEL=gpt-4
|
|
81
|
+
LLM_API_KEY=your_api_key_here
|
|
82
|
+
LLM_BASE_URL=https://api.openai.com/v1
|
|
83
|
+
|
|
84
|
+
# Telegram Bot (optional)
|
|
85
|
+
TELEGRAM_BOT_TOKEN=your_bot_token
|
|
86
|
+
TELEGRAM_BOT_TOKEN_LOG=your_log_bot_token
|
|
87
|
+
TELEGRAM_USER_IDS=your_user_id
|
|
88
|
+
|
|
89
|
+
# Agent Settings
|
|
90
|
+
AGENT_MAX_CONCURRENT_AGENTS=10
|
|
91
|
+
AGENT_ENABLE_REFLECTION=true
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
See [.env.example](.env.example) for all available options.
|
|
95
|
+
|
|
96
|
+
## Agent Profiles
|
|
97
|
+
|
|
98
|
+
NixClaw includes 6 specialist agent profiles:
|
|
99
|
+
|
|
100
|
+
| Profile | Description |
|
|
101
|
+
|---------|-------------|
|
|
102
|
+
| **CodeGenerator** | Generates, modifies, and refactors code |
|
|
103
|
+
| **Analyzer** | Analyzes code, data, and systems for insights |
|
|
104
|
+
| **Researcher** | Gathers information and synthesizes findings |
|
|
105
|
+
| **SystemAdmin** | Executes system commands and manages infrastructure |
|
|
106
|
+
| **Debugger** | Investigates and fixes bugs systematically |
|
|
107
|
+
| **General** | General-purpose agent for miscellaneous tasks |
|
|
108
|
+
|
|
109
|
+
## REST API
|
|
110
|
+
|
|
111
|
+
Start the API server:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
nixclaw --serve --port 8000
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Endpoints:
|
|
118
|
+
|
|
119
|
+
| Method | Path | Description |
|
|
120
|
+
|--------|------|-------------|
|
|
121
|
+
| POST | `/api/v1/tasks` | Submit a task |
|
|
122
|
+
| GET | `/api/v1/tasks/{id}` | Get task status |
|
|
123
|
+
| GET | `/api/v1/tasks` | List all tasks |
|
|
124
|
+
| POST | `/api/v1/tasks/{id}/cancel` | Cancel a task |
|
|
125
|
+
| GET | `/api/v1/agents/status` | Agent overview |
|
|
126
|
+
| GET | `/api/v1/health` | Health check |
|
|
127
|
+
|
|
128
|
+
## Telegram Integration
|
|
129
|
+
|
|
130
|
+
NixClaw supports two Telegram bots:
|
|
131
|
+
|
|
132
|
+
- **Primary bot** (`TELEGRAM_BOT_TOKEN`): Receives commands (`/task`, `/status`, `/agents`) and sends task notifications
|
|
133
|
+
- **Log bot** (`TELEGRAM_BOT_TOKEN_LOG`): Mirrors all output from CLI, API, and Telegram to a dedicated log channel
|
|
134
|
+
|
|
135
|
+
## Architecture
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
nixclaw/
|
|
139
|
+
├── agents/ # Agent system (orchestrator, factory, profiles)
|
|
140
|
+
├── tools/ # Built-in tools (file ops, shell, search)
|
|
141
|
+
├── core/ # Task manager, context, event bus, retry, security
|
|
142
|
+
├── storage/ # Database persistence (SQLAlchemy + SQLite)
|
|
143
|
+
├── api/ # REST API (FastAPI)
|
|
144
|
+
└── integrations/ # Telegram, webhooks, LLM client
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## License
|
|
148
|
+
|
|
149
|
+
MIT
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""NixClaw - Multi-Agent AI System built on AutoGen.
|
|
2
|
+
|
|
3
|
+
Usage as a library:
|
|
4
|
+
from nixclaw import Orchestrator, AgentFactory, ManagedAgent
|
|
5
|
+
|
|
6
|
+
orchestrator = Orchestrator()
|
|
7
|
+
result = await orchestrator.run("Your task here")
|
|
8
|
+
|
|
9
|
+
Usage as CLI:
|
|
10
|
+
nixclaw "Your task here"
|
|
11
|
+
nixclaw --interactive
|
|
12
|
+
python -m nixclaw "Your task here"
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
__version__ = "0.1.0"
|
|
16
|
+
|
|
17
|
+
from nixclaw.agents.orchestrator import Orchestrator
|
|
18
|
+
from nixclaw.agents.agent_factory import AgentFactory
|
|
19
|
+
from nixclaw.agents.base_agent import ManagedAgent, create_model_client
|
|
20
|
+
from nixclaw.agents.agent_profiles import get_profile, list_profiles
|
|
21
|
+
from nixclaw.core.task_manager import TaskManager
|
|
22
|
+
from nixclaw.core.context_manager import ContextManager
|
|
23
|
+
from nixclaw.core.event_bus import EventBus
|
|
24
|
+
from nixclaw.core.async_task_queue import AsyncTaskQueue, get_task_queue
|
|
25
|
+
from nixclaw.config import get_settings
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"Orchestrator",
|
|
29
|
+
"AgentFactory",
|
|
30
|
+
"ManagedAgent",
|
|
31
|
+
"create_model_client",
|
|
32
|
+
"get_profile",
|
|
33
|
+
"list_profiles",
|
|
34
|
+
"TaskManager",
|
|
35
|
+
"ContextManager",
|
|
36
|
+
"EventBus",
|
|
37
|
+
"AsyncTaskQueue",
|
|
38
|
+
"get_task_queue",
|
|
39
|
+
"get_settings",
|
|
40
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from datetime import datetime, timezone
|
|
5
|
+
|
|
6
|
+
from nixclaw.agents.base_agent import ManagedAgent, create_model_client
|
|
7
|
+
from nixclaw.agents.agent_profiles import get_profile
|
|
8
|
+
from nixclaw.config import get_settings
|
|
9
|
+
from nixclaw.logger import get_logger
|
|
10
|
+
from nixclaw.storage.models import AgentStatus
|
|
11
|
+
|
|
12
|
+
logger = get_logger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AgentFactory:
|
|
16
|
+
"""Creates, tracks, and manages agent instances.
|
|
17
|
+
|
|
18
|
+
Implements the Agent Factory pattern: agents are created on-demand
|
|
19
|
+
from profiles, tracked for lifecycle management, and cleaned up
|
|
20
|
+
when no longer needed.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
_instance: AgentFactory | None = None
|
|
24
|
+
|
|
25
|
+
def __init__(self) -> None:
|
|
26
|
+
self._agents: dict[str, ManagedAgent] = {}
|
|
27
|
+
self._lock = asyncio.Lock()
|
|
28
|
+
self._counter: int = 0
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def get_instance(cls) -> AgentFactory:
|
|
32
|
+
if cls._instance is None:
|
|
33
|
+
cls._instance = cls()
|
|
34
|
+
return cls._instance
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def reset(cls) -> None:
|
|
38
|
+
cls._instance = None
|
|
39
|
+
|
|
40
|
+
def _next_name(self, base: str) -> str:
|
|
41
|
+
self._counter += 1
|
|
42
|
+
return f"{base}_{self._counter}"
|
|
43
|
+
|
|
44
|
+
async def create_agent(
|
|
45
|
+
self,
|
|
46
|
+
profile_name: str,
|
|
47
|
+
custom_system_message: str | None = None,
|
|
48
|
+
) -> ManagedAgent:
|
|
49
|
+
"""Create a new agent from a profile template."""
|
|
50
|
+
settings = get_settings()
|
|
51
|
+
|
|
52
|
+
# Enforce concurrency limit
|
|
53
|
+
active = sum(
|
|
54
|
+
1
|
|
55
|
+
for a in self._agents.values()
|
|
56
|
+
if a.metadata.status in (AgentStatus.IDLE, AgentStatus.BUSY)
|
|
57
|
+
)
|
|
58
|
+
if active >= settings.agent.max_concurrent_agents:
|
|
59
|
+
raise RuntimeError(
|
|
60
|
+
f"Max concurrent agents reached ({settings.agent.max_concurrent_agents}). "
|
|
61
|
+
"Wait for existing agents to complete."
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
profile = get_profile(profile_name)
|
|
65
|
+
name = self._next_name(profile.name)
|
|
66
|
+
system_msg = custom_system_message or profile.system_message
|
|
67
|
+
|
|
68
|
+
agent = ManagedAgent(
|
|
69
|
+
name=name,
|
|
70
|
+
system_message=system_msg,
|
|
71
|
+
tools=profile.tools,
|
|
72
|
+
profile=profile_name,
|
|
73
|
+
description=profile.description,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
async with self._lock:
|
|
77
|
+
self._agents[agent.metadata.id] = agent
|
|
78
|
+
|
|
79
|
+
logger.info(
|
|
80
|
+
"Factory created agent: name=%s profile=%s id=%s (active=%d)",
|
|
81
|
+
name,
|
|
82
|
+
profile_name,
|
|
83
|
+
agent.metadata.id,
|
|
84
|
+
active + 1,
|
|
85
|
+
)
|
|
86
|
+
return agent
|
|
87
|
+
|
|
88
|
+
async def create_and_run(
|
|
89
|
+
self,
|
|
90
|
+
profile_name: str,
|
|
91
|
+
task: str,
|
|
92
|
+
context: str = "",
|
|
93
|
+
priority: str = "normal",
|
|
94
|
+
) -> str:
|
|
95
|
+
"""Create a specialist agent, run a task, and return the text result."""
|
|
96
|
+
agent = await self.create_agent(profile_name)
|
|
97
|
+
|
|
98
|
+
full_task = task
|
|
99
|
+
if context:
|
|
100
|
+
full_task = f"Context:\n{context}\n\nTask:\n{task}"
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
result = await agent.run(task=full_task)
|
|
104
|
+
text = agent.get_result_text(result)
|
|
105
|
+
logger.info(
|
|
106
|
+
"Agent '%s' completed task (profile=%s): %.100s...",
|
|
107
|
+
agent.name,
|
|
108
|
+
profile_name,
|
|
109
|
+
text,
|
|
110
|
+
)
|
|
111
|
+
return text or "(no output from agent)"
|
|
112
|
+
except Exception as e:
|
|
113
|
+
logger.exception("Agent '%s' failed task: %s", agent.name, e)
|
|
114
|
+
return f"Agent error ({profile_name}): {e}"
|
|
115
|
+
finally:
|
|
116
|
+
await self.release_agent(agent.metadata.id)
|
|
117
|
+
|
|
118
|
+
async def get_agent(self, agent_id: str) -> ManagedAgent | None:
|
|
119
|
+
return self._agents.get(agent_id)
|
|
120
|
+
|
|
121
|
+
async def release_agent(self, agent_id: str) -> None:
|
|
122
|
+
"""Release an agent and clean up resources."""
|
|
123
|
+
async with self._lock:
|
|
124
|
+
agent = self._agents.pop(agent_id, None)
|
|
125
|
+
if agent:
|
|
126
|
+
await agent.close()
|
|
127
|
+
logger.info("Released agent: %s (id=%s)", agent.name, agent_id)
|
|
128
|
+
|
|
129
|
+
async def find_idle_agent(self, profile_name: str) -> ManagedAgent | None:
|
|
130
|
+
"""Find an existing idle agent matching the profile."""
|
|
131
|
+
for agent in self._agents.values():
|
|
132
|
+
if (
|
|
133
|
+
agent.metadata.profile == profile_name
|
|
134
|
+
and agent.metadata.status == AgentStatus.IDLE
|
|
135
|
+
):
|
|
136
|
+
return agent
|
|
137
|
+
return None
|
|
138
|
+
|
|
139
|
+
async def cleanup_all(self) -> None:
|
|
140
|
+
"""Terminate and clean up all agents."""
|
|
141
|
+
async with self._lock:
|
|
142
|
+
agents = list(self._agents.values())
|
|
143
|
+
self._agents.clear()
|
|
144
|
+
for agent in agents:
|
|
145
|
+
await agent.close()
|
|
146
|
+
logger.info("Cleaned up %d agents", len(agents))
|
|
147
|
+
|
|
148
|
+
def get_status(self) -> dict:
|
|
149
|
+
"""Get a summary of all agent states."""
|
|
150
|
+
summary: dict[str, int] = {}
|
|
151
|
+
for agent in self._agents.values():
|
|
152
|
+
status = agent.metadata.status.value
|
|
153
|
+
summary[status] = summary.get(status, 0) + 1
|
|
154
|
+
return {
|
|
155
|
+
"total": len(self._agents),
|
|
156
|
+
"by_status": summary,
|
|
157
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Callable, Any
|
|
5
|
+
|
|
6
|
+
from nixclaw.tools.file_operations import read_file, write_file, delete_file
|
|
7
|
+
from nixclaw.tools.directory_ops import list_dir, create_dir
|
|
8
|
+
from nixclaw.tools.search_tools import search_files, search_content
|
|
9
|
+
from nixclaw.tools.shell_executor import execute_shell_command
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class AgentProfile:
|
|
14
|
+
"""Template for creating specialized agents."""
|
|
15
|
+
|
|
16
|
+
name: str
|
|
17
|
+
system_message: str
|
|
18
|
+
description: str
|
|
19
|
+
tools: list[Callable[..., Any]] = field(default_factory=list)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# ── Core tool sets ───────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
FILE_TOOLS: list[Callable[..., Any]] = [read_file, write_file, delete_file]
|
|
25
|
+
DIR_TOOLS: list[Callable[..., Any]] = [list_dir, create_dir]
|
|
26
|
+
SEARCH_TOOLS: list[Callable[..., Any]] = [search_files, search_content]
|
|
27
|
+
SHELL_TOOLS: list[Callable[..., Any]] = [execute_shell_command]
|
|
28
|
+
ALL_TOOLS: list[Callable[..., Any]] = FILE_TOOLS + DIR_TOOLS + SEARCH_TOOLS + SHELL_TOOLS
|
|
29
|
+
|
|
30
|
+
# ── Pre-defined profiles ────────────────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
PROFILES: dict[str, AgentProfile] = {
|
|
33
|
+
"CodeGenerator": AgentProfile(
|
|
34
|
+
name="code_generator",
|
|
35
|
+
description="Generates, modifies, and refactors code",
|
|
36
|
+
system_message=(
|
|
37
|
+
"You are an expert code generator. You write clean, efficient, well-structured code. "
|
|
38
|
+
"You have access to file operations and shell commands. "
|
|
39
|
+
"When writing code:\n"
|
|
40
|
+
"- Follow best practices for the language\n"
|
|
41
|
+
"- Add minimal but clear comments for non-obvious logic\n"
|
|
42
|
+
"- Handle edge cases and errors\n"
|
|
43
|
+
"- Use the provided tools to read existing code, write new files, and test your work\n"
|
|
44
|
+
"Report your results clearly when done."
|
|
45
|
+
),
|
|
46
|
+
tools=ALL_TOOLS,
|
|
47
|
+
),
|
|
48
|
+
"Analyzer": AgentProfile(
|
|
49
|
+
name="analyzer",
|
|
50
|
+
description="Analyzes code, data, and systems for insights and issues",
|
|
51
|
+
system_message=(
|
|
52
|
+
"You are an expert analyst. You examine code, data, logs, and system state to provide "
|
|
53
|
+
"clear, actionable insights. You can:\n"
|
|
54
|
+
"- Read and analyze source code for bugs, patterns, and improvements\n"
|
|
55
|
+
"- Search codebases for specific patterns or issues\n"
|
|
56
|
+
"- Analyze command output and logs\n"
|
|
57
|
+
"- Provide structured analysis with severity levels\n"
|
|
58
|
+
"Always provide evidence-based conclusions with specific file/line references."
|
|
59
|
+
),
|
|
60
|
+
tools=FILE_TOOLS + DIR_TOOLS + SEARCH_TOOLS,
|
|
61
|
+
),
|
|
62
|
+
"Researcher": AgentProfile(
|
|
63
|
+
name="researcher",
|
|
64
|
+
description="Researches topics, gathers information, and synthesizes findings",
|
|
65
|
+
system_message=(
|
|
66
|
+
"You are a thorough researcher. You gather information from available sources, "
|
|
67
|
+
"analyze it, and synthesize clear findings. You can:\n"
|
|
68
|
+
"- Search files and directories for relevant information\n"
|
|
69
|
+
"- Read documentation and code to understand systems\n"
|
|
70
|
+
"- Compile findings into structured summaries\n"
|
|
71
|
+
"Always cite your sources (file paths, line numbers) and distinguish facts from inferences."
|
|
72
|
+
),
|
|
73
|
+
tools=FILE_TOOLS + DIR_TOOLS + SEARCH_TOOLS,
|
|
74
|
+
),
|
|
75
|
+
"SystemAdmin": AgentProfile(
|
|
76
|
+
name="system_admin",
|
|
77
|
+
description="Executes system commands, manages processes and infrastructure",
|
|
78
|
+
system_message=(
|
|
79
|
+
"You are an experienced system administrator. You manage system operations safely "
|
|
80
|
+
"and efficiently. You can:\n"
|
|
81
|
+
"- Execute shell commands with proper safety checks\n"
|
|
82
|
+
"- Manage files and directories\n"
|
|
83
|
+
"- Monitor system state and processes\n"
|
|
84
|
+
"- Install and configure software\n"
|
|
85
|
+
"Always explain what commands will do before executing them. "
|
|
86
|
+
"Prefer safe, reversible operations. Report command output clearly."
|
|
87
|
+
),
|
|
88
|
+
tools=ALL_TOOLS,
|
|
89
|
+
),
|
|
90
|
+
"Debugger": AgentProfile(
|
|
91
|
+
name="debugger",
|
|
92
|
+
description="Investigates and fixes bugs, errors, and failures",
|
|
93
|
+
system_message=(
|
|
94
|
+
"You are an expert debugger. You systematically identify and fix bugs. Your approach:\n"
|
|
95
|
+
"1. Reproduce: Understand the error and its context\n"
|
|
96
|
+
"2. Investigate: Search code, read logs, trace execution paths\n"
|
|
97
|
+
"3. Diagnose: Identify the root cause with evidence\n"
|
|
98
|
+
"4. Fix: Apply the minimal correct fix\n"
|
|
99
|
+
"5. Verify: Test that the fix works\n"
|
|
100
|
+
"Always explain your reasoning and show evidence for your diagnosis."
|
|
101
|
+
),
|
|
102
|
+
tools=ALL_TOOLS,
|
|
103
|
+
),
|
|
104
|
+
"General": AgentProfile(
|
|
105
|
+
name="general_assistant",
|
|
106
|
+
description="General-purpose agent for miscellaneous tasks",
|
|
107
|
+
system_message=(
|
|
108
|
+
"You are a capable general-purpose assistant. You handle a variety of tasks "
|
|
109
|
+
"using the tools available to you. Be concise and effective. "
|
|
110
|
+
"Use the most appropriate tools for each task and report results clearly."
|
|
111
|
+
),
|
|
112
|
+
tools=ALL_TOOLS,
|
|
113
|
+
),
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def get_profile(name: str) -> AgentProfile:
|
|
118
|
+
"""Get an agent profile by name. Falls back to General if not found."""
|
|
119
|
+
profile = PROFILES.get(name)
|
|
120
|
+
if profile is None:
|
|
121
|
+
profile = PROFILES["General"]
|
|
122
|
+
return profile
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def list_profiles() -> list[str]:
|
|
126
|
+
"""List all available profile names."""
|
|
127
|
+
return list(PROFILES.keys())
|