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.
Files changed (51) hide show
  1. nixclaw-0.1.0/LICENSE +21 -0
  2. nixclaw-0.1.0/PKG-INFO +195 -0
  3. nixclaw-0.1.0/README.md +149 -0
  4. nixclaw-0.1.0/nixclaw/__init__.py +40 -0
  5. nixclaw-0.1.0/nixclaw/__main__.py +4 -0
  6. nixclaw-0.1.0/nixclaw/agents/__init__.py +0 -0
  7. nixclaw-0.1.0/nixclaw/agents/agent_factory.py +157 -0
  8. nixclaw-0.1.0/nixclaw/agents/agent_profiles.py +127 -0
  9. nixclaw-0.1.0/nixclaw/agents/base_agent.py +111 -0
  10. nixclaw-0.1.0/nixclaw/agents/orchestrator.py +198 -0
  11. nixclaw-0.1.0/nixclaw/api/__init__.py +0 -0
  12. nixclaw-0.1.0/nixclaw/api/app.py +31 -0
  13. nixclaw-0.1.0/nixclaw/api/routes.py +94 -0
  14. nixclaw-0.1.0/nixclaw/api/schemas.py +37 -0
  15. nixclaw-0.1.0/nixclaw/config.py +108 -0
  16. nixclaw-0.1.0/nixclaw/core/__init__.py +0 -0
  17. nixclaw-0.1.0/nixclaw/core/async_task_queue.py +223 -0
  18. nixclaw-0.1.0/nixclaw/core/command_executor.py +129 -0
  19. nixclaw-0.1.0/nixclaw/core/context_manager.py +84 -0
  20. nixclaw-0.1.0/nixclaw/core/event_bus.py +80 -0
  21. nixclaw-0.1.0/nixclaw/core/health.py +89 -0
  22. nixclaw-0.1.0/nixclaw/core/retry.py +81 -0
  23. nixclaw-0.1.0/nixclaw/core/security.py +52 -0
  24. nixclaw-0.1.0/nixclaw/core/task_manager.py +176 -0
  25. nixclaw-0.1.0/nixclaw/integrations/__init__.py +0 -0
  26. nixclaw-0.1.0/nixclaw/integrations/openai_client.py +37 -0
  27. nixclaw-0.1.0/nixclaw/integrations/telegram_bot.py +295 -0
  28. nixclaw-0.1.0/nixclaw/integrations/telegram_log.py +203 -0
  29. nixclaw-0.1.0/nixclaw/integrations/webhooks.py +59 -0
  30. nixclaw-0.1.0/nixclaw/logger.py +62 -0
  31. nixclaw-0.1.0/nixclaw/main.py +175 -0
  32. nixclaw-0.1.0/nixclaw/storage/__init__.py +0 -0
  33. nixclaw-0.1.0/nixclaw/storage/cache.py +14 -0
  34. nixclaw-0.1.0/nixclaw/storage/database.py +135 -0
  35. nixclaw-0.1.0/nixclaw/storage/models.py +132 -0
  36. nixclaw-0.1.0/nixclaw/storage/repository.py +207 -0
  37. nixclaw-0.1.0/nixclaw/tools/__init__.py +0 -0
  38. nixclaw-0.1.0/nixclaw/tools/agent_tool.py +35 -0
  39. nixclaw-0.1.0/nixclaw/tools/directory_ops.py +62 -0
  40. nixclaw-0.1.0/nixclaw/tools/file_operations.py +67 -0
  41. nixclaw-0.1.0/nixclaw/tools/search_tools.py +111 -0
  42. nixclaw-0.1.0/nixclaw/tools/shell_executor.py +209 -0
  43. nixclaw-0.1.0/nixclaw/tools/telegram_tool.py +44 -0
  44. nixclaw-0.1.0/nixclaw.egg-info/PKG-INFO +195 -0
  45. nixclaw-0.1.0/nixclaw.egg-info/SOURCES.txt +49 -0
  46. nixclaw-0.1.0/nixclaw.egg-info/dependency_links.txt +1 -0
  47. nixclaw-0.1.0/nixclaw.egg-info/entry_points.txt +2 -0
  48. nixclaw-0.1.0/nixclaw.egg-info/requires.txt +28 -0
  49. nixclaw-0.1.0/nixclaw.egg-info/top_level.txt +1 -0
  50. nixclaw-0.1.0/pyproject.toml +63 -0
  51. 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
@@ -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
+ ]
@@ -0,0 +1,4 @@
1
+ """Allow running as: python -m nixclaw"""
2
+ from nixclaw.main import main
3
+
4
+ main()
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())