localist 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.
- localist-0.1.0/.env.example +32 -0
- localist-0.1.0/.gitignore +42 -0
- localist-0.1.0/CHANGELOG.md +24 -0
- localist-0.1.0/LICENSE +21 -0
- localist-0.1.0/MANIFEST.in +2 -0
- localist-0.1.0/PKG-INFO +269 -0
- localist-0.1.0/README.md +224 -0
- localist-0.1.0/pyproject.toml +96 -0
- localist-0.1.0/src/localist/__init__.py +43 -0
- localist-0.1.0/src/localist/agent.py +428 -0
- localist-0.1.0/src/localist/cli.py +270 -0
- localist-0.1.0/src/localist/config.py +119 -0
- localist-0.1.0/src/localist/confirmation.py +99 -0
- localist-0.1.0/src/localist/exceptions.py +71 -0
- localist-0.1.0/src/localist/logger.py +107 -0
- localist-0.1.0/src/localist/protocol.py +211 -0
- localist-0.1.0/src/localist/registry.py +258 -0
- localist-0.1.0/src/localist/sandbox.py +80 -0
- localist-0.1.0/src/localist/tools/__init__.py +9 -0
- localist-0.1.0/src/localist/tools/filesystem.py +197 -0
- localist-0.1.0/src/localist/tools/os_tools.py +148 -0
- localist-0.1.0/src/localist/tools/shell.py +118 -0
- localist-0.1.0/src/localist/tools/web.py +185 -0
- localist-0.1.0/src/localist/ui/__init__.py +6 -0
- localist-0.1.0/src/localist/ui/server.py +271 -0
- localist-0.1.0/src/localist/ui/static/app.js +448 -0
- localist-0.1.0/src/localist/ui/static/index.html +130 -0
- localist-0.1.0/src/localist/ui/static/style.css +779 -0
- localist-0.1.0/tests/__init__.py +1 -0
- localist-0.1.0/tests/test_agent.py +149 -0
- localist-0.1.0/tests/test_registry.py +89 -0
- localist-0.1.0/tests/test_sandbox.py +79 -0
- localist-0.1.0/tests/test_tools.py +152 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Environment configuration for Localist
|
|
2
|
+
# Copy this file to .env and fill in your values
|
|
3
|
+
|
|
4
|
+
# ── Ollama ──────────────────────────────────────────────────────────────────
|
|
5
|
+
OLLAMA_BASE_URL=http://localhost:11434
|
|
6
|
+
LOCALIST_MODEL=qwen2.5:7b
|
|
7
|
+
|
|
8
|
+
# ── Workspace ────────────────────────────────────────────────────────────────
|
|
9
|
+
# All file operations are sandboxed inside this directory
|
|
10
|
+
LOCALIST_WORKSPACE_ROOT=./workspace
|
|
11
|
+
|
|
12
|
+
# ── Agent loop ───────────────────────────────────────────────────────────────
|
|
13
|
+
LOCALIST_MAX_ITERATIONS=20
|
|
14
|
+
|
|
15
|
+
# ── Safety ───────────────────────────────────────────────────────────────────
|
|
16
|
+
# Set to false to disable confirmation prompts (e.g., in automated pipelines)
|
|
17
|
+
LOCALIST_REQUIRE_CONFIRMATION=true
|
|
18
|
+
|
|
19
|
+
# Comma-separated list of tools that require explicit confirmation
|
|
20
|
+
LOCALIST_CONFIRMATION_TOOLS=file_delete,shell_exec,process_kill
|
|
21
|
+
|
|
22
|
+
# ── Logging ──────────────────────────────────────────────────────────────────
|
|
23
|
+
LOCALIST_LOG_DIR=./logs
|
|
24
|
+
LOCALIST_LOG_LEVEL=INFO
|
|
25
|
+
|
|
26
|
+
# ── Web Search ───────────────────────────────────────────────────────────────
|
|
27
|
+
# Optional: set to use Brave Search API instead of DuckDuckGo
|
|
28
|
+
BRAVE_API_KEY=
|
|
29
|
+
|
|
30
|
+
# ── Web UI (optional, requires: pip install localist[ui]) ────────────────────
|
|
31
|
+
LOCALIST_UI_HOST=127.0.0.1
|
|
32
|
+
LOCALIST_UI_PORT=7860
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
*.egg
|
|
7
|
+
*.egg-info/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
.eggs/
|
|
11
|
+
.venv/
|
|
12
|
+
venv/
|
|
13
|
+
env/
|
|
14
|
+
|
|
15
|
+
# Distribution
|
|
16
|
+
dist/
|
|
17
|
+
*.whl
|
|
18
|
+
*.tar.gz
|
|
19
|
+
|
|
20
|
+
# Environment
|
|
21
|
+
.env
|
|
22
|
+
!.env.example
|
|
23
|
+
|
|
24
|
+
# Localist runtime
|
|
25
|
+
workspace/
|
|
26
|
+
logs/
|
|
27
|
+
|
|
28
|
+
# Testing
|
|
29
|
+
.pytest_cache/
|
|
30
|
+
.coverage
|
|
31
|
+
htmlcov/
|
|
32
|
+
.mypy_cache/
|
|
33
|
+
.ruff_cache/
|
|
34
|
+
|
|
35
|
+
# IDE
|
|
36
|
+
.vscode/
|
|
37
|
+
.idea/
|
|
38
|
+
*.swp
|
|
39
|
+
*.swo
|
|
40
|
+
|
|
41
|
+
# macOS
|
|
42
|
+
.DS_Store
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-09-13
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Initial release of `localist`
|
|
12
|
+
- ReAct agent loop with dual protocol support (native tool-calling + text-based)
|
|
13
|
+
- Filesystem tools: `file_read`, `file_write`, `file_append`, `file_delete`, `list_dir`
|
|
14
|
+
- Web tools: `web_search` (DuckDuckGo + Brave Search), `web_fetch`
|
|
15
|
+
- Shell tool: `shell_exec` with allowlist/denylist safety
|
|
16
|
+
- OS tools: `clipboard_get`, `clipboard_set`, `notify`, `process_list`, `process_kill`
|
|
17
|
+
- Filesystem sandbox jail (path traversal protection)
|
|
18
|
+
- Human-in-the-loop confirmation gate for destructive operations
|
|
19
|
+
- Structured JSON audit logging
|
|
20
|
+
- `@register_tool` decorator for custom tools
|
|
21
|
+
- Rich CLI with `localist` entry point
|
|
22
|
+
- Optional FastAPI web UI (`pip install localist[ui]`)
|
|
23
|
+
- Automatic model capability detection (native vs. text-protocol)
|
|
24
|
+
- Retry/repair logic for malformed JSON tool calls
|
localist-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Localist Contributors
|
|
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.
|
localist-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: localist
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Local agentic framework on Ollama — filesystem, web, shell & OS tools with a sandboxed ReAct loop
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: agent,agentic,autonomous,llm,local-ai,ollama,react,tool-calling
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Requires-Dist: duckduckgo-search>=6.0
|
|
21
|
+
Requires-Dist: httpx>=0.27
|
|
22
|
+
Requires-Dist: ollama>=0.3
|
|
23
|
+
Requires-Dist: plyer>=2.1
|
|
24
|
+
Requires-Dist: psutil>=5.9
|
|
25
|
+
Requires-Dist: pydantic-settings>=2.0
|
|
26
|
+
Requires-Dist: pydantic>=2.0
|
|
27
|
+
Requires-Dist: pyperclip>=1.8
|
|
28
|
+
Requires-Dist: python-dotenv>=1.0
|
|
29
|
+
Requires-Dist: rich>=13.0
|
|
30
|
+
Requires-Dist: trafilatura>=1.12
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: build>=1.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
38
|
+
Requires-Dist: twine>=5.0; extra == 'dev'
|
|
39
|
+
Requires-Dist: types-psutil; extra == 'dev'
|
|
40
|
+
Provides-Extra: ui
|
|
41
|
+
Requires-Dist: fastapi>=0.111; extra == 'ui'
|
|
42
|
+
Requires-Dist: python-multipart>=0.0.9; extra == 'ui'
|
|
43
|
+
Requires-Dist: uvicorn[standard]>=0.30; extra == 'ui'
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
|
|
46
|
+
# localist
|
|
47
|
+
|
|
48
|
+
**Local agentic framework on Ollama** — give your local LLM sandboxed access to filesystem, web, shell, and OS tools via a ReAct reasoning loop.
|
|
49
|
+
|
|
50
|
+
[](https://pypi.org/project/localist/)
|
|
51
|
+
[](https://python.org)
|
|
52
|
+
[](LICENSE)
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## What is this?
|
|
57
|
+
|
|
58
|
+
`localist` is a Python library that wraps any [Ollama](https://ollama.ai)-served model and gives it the ability to autonomously:
|
|
59
|
+
|
|
60
|
+
- 📂 **Read / write / delete files** inside a sandboxed workspace
|
|
61
|
+
- 🌐 **Search the web** (DuckDuckGo, or Brave Search API)
|
|
62
|
+
- 🖥️ **Run shell commands** (behind a denylist + confirmation gate)
|
|
63
|
+
- 📋 **Use OS features** — clipboard, notifications, process management
|
|
64
|
+
|
|
65
|
+
It implements a **ReAct-style loop** (Reason → Act → Observe → repeat) and supports both models with native tool-calling (Qwen2.5, Llama 3.1+) and text-based tool-calling for any other model.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Quick Start
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Install
|
|
73
|
+
pip install localist
|
|
74
|
+
|
|
75
|
+
# Make sure Ollama is running
|
|
76
|
+
ollama serve
|
|
77
|
+
ollama pull qwen2.5:7b
|
|
78
|
+
|
|
79
|
+
# Run a task
|
|
80
|
+
localist --task "Create a file called hello.txt with today's date, then list the workspace"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Installation
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Core library + CLI
|
|
89
|
+
pip install localist
|
|
90
|
+
|
|
91
|
+
# With web UI (FastAPI + Uvicorn)
|
|
92
|
+
pip install "localist[ui]"
|
|
93
|
+
|
|
94
|
+
# Development
|
|
95
|
+
pip install "localist[dev]"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Usage
|
|
101
|
+
|
|
102
|
+
### Python API
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from localist import Agent
|
|
106
|
+
|
|
107
|
+
agent = Agent(model="qwen2.5:7b", workspace_root="./workspace")
|
|
108
|
+
result = agent.run("Search for the latest Python release and save a summary to workspace/python_news.txt")
|
|
109
|
+
print(result)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Streaming events
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from localist import Agent
|
|
116
|
+
from localist.agent import ToolCallEvent, FinalAnswerEvent
|
|
117
|
+
|
|
118
|
+
agent = Agent(model="qwen2.5:7b")
|
|
119
|
+
|
|
120
|
+
for event in agent.stream("Summarise all .txt files in workspace"):
|
|
121
|
+
if isinstance(event, ToolCallEvent):
|
|
122
|
+
print(f" 🔧 Calling: {event.tool}({event.args})")
|
|
123
|
+
elif isinstance(event, FinalAnswerEvent):
|
|
124
|
+
print(f"\n✅ Answer:\n{event.content}")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Custom tools
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
from localist import Agent, register_tool
|
|
131
|
+
|
|
132
|
+
@register_tool
|
|
133
|
+
def count_words(text: str) -> int:
|
|
134
|
+
"""Count the number of words in a text string.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
text: The input text to count words in.
|
|
138
|
+
"""
|
|
139
|
+
return len(text.split())
|
|
140
|
+
|
|
141
|
+
agent = Agent(model="qwen2.5:7b")
|
|
142
|
+
result = agent.run("Count the words in 'The quick brown fox jumps over the lazy dog'")
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### CLI
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# Single task
|
|
149
|
+
localist --task "Create a Python script that generates the Fibonacci sequence"
|
|
150
|
+
|
|
151
|
+
# Custom model and workspace
|
|
152
|
+
localist --task "..." --model llama3.1:8b --workspace ~/myproject
|
|
153
|
+
|
|
154
|
+
# Interactive REPL
|
|
155
|
+
localist --interactive
|
|
156
|
+
|
|
157
|
+
# Web UI (requires pip install localist[ui])
|
|
158
|
+
localist --ui
|
|
159
|
+
|
|
160
|
+
# List available Ollama models
|
|
161
|
+
localist --list-models
|
|
162
|
+
|
|
163
|
+
# Disable confirmation prompts (for scripts/automation)
|
|
164
|
+
localist --task "..." --no-confirm
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Tools
|
|
170
|
+
|
|
171
|
+
| Tool | Description | Confirmation required? |
|
|
172
|
+
|---|---|---|
|
|
173
|
+
| `file_read` | Read file contents | No |
|
|
174
|
+
| `file_write` | Create/overwrite a file | No (overwrite) |
|
|
175
|
+
| `file_append` | Append to a file | No |
|
|
176
|
+
| `file_delete` | Delete a file | **Yes** |
|
|
177
|
+
| `list_dir` | List directory contents | No |
|
|
178
|
+
| `web_search` | Search web (DuckDuckGo / Brave) | No |
|
|
179
|
+
| `web_fetch` | Fetch and extract text from URL | No |
|
|
180
|
+
| `shell_exec` | Run a shell command | **Yes** |
|
|
181
|
+
| `clipboard_get` | Read clipboard | No |
|
|
182
|
+
| `clipboard_set` | Write clipboard | No |
|
|
183
|
+
| `notify` | OS desktop notification | No |
|
|
184
|
+
| `process_list` | List running processes | No |
|
|
185
|
+
| `process_kill` | Terminate a process by PID | **Yes** |
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Configuration
|
|
190
|
+
|
|
191
|
+
Copy `.env.example` to `.env` and edit:
|
|
192
|
+
|
|
193
|
+
```env
|
|
194
|
+
LOCALIST_MODEL=qwen2.5:7b
|
|
195
|
+
LOCALIST_WORKSPACE_ROOT=./workspace
|
|
196
|
+
LOCALIST_MAX_ITERATIONS=20
|
|
197
|
+
LOCALIST_REQUIRE_CONFIRMATION=true
|
|
198
|
+
BRAVE_API_KEY= # optional — enables Brave Search API
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
All settings can also be passed programmatically:
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
from localist.config import LocalistConfig
|
|
205
|
+
from localist import Agent
|
|
206
|
+
|
|
207
|
+
cfg = LocalistConfig(model="llama3.1:8b", max_iterations=10, require_confirmation=False)
|
|
208
|
+
agent = Agent(config=cfg)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Safety
|
|
214
|
+
|
|
215
|
+
- **Filesystem jail**: every path is resolved against `workspace_root`; `..` traversal, symlink escapes, and absolute paths outside the workspace are rejected with `SandboxViolationError`.
|
|
216
|
+
- **Shell denylist**: `shell_exec` blocks `rm`, `sudo`, `curl`, `python`, shell interpreters, and other high-risk binaries. No `shell=True` anywhere.
|
|
217
|
+
- **Confirmation gate**: `file_delete`, `shell_exec`, and `process_kill` require explicit human approval (configurable).
|
|
218
|
+
- **Hard iteration cap**: the loop stops after `max_iterations` (default: 20) to prevent infinite loops.
|
|
219
|
+
- **Audit logging**: every tool call, result, and confirmation is written to `logs/audit_<date>.jsonl`.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Model Recommendations
|
|
224
|
+
|
|
225
|
+
| Model | Tool-calling | Notes |
|
|
226
|
+
|---|---|---|
|
|
227
|
+
| `qwen2.5:7b` / `qwen2.5:32b` | Native | Best balance of speed and reliability |
|
|
228
|
+
| `llama3.1:8b` / `llama3.3:70b` | Native | Strong general reasoning |
|
|
229
|
+
| `hermes3` | Native | Optimised for agentic tasks |
|
|
230
|
+
| `mistral-nemo` | Native | Fast, solid tool support |
|
|
231
|
+
| Any other model | Text protocol | Automatic fallback with JSON repair |
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Build and Publish
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# Install build tools
|
|
239
|
+
pip install build twine
|
|
240
|
+
|
|
241
|
+
# Build
|
|
242
|
+
python -m build
|
|
243
|
+
|
|
244
|
+
# Validate
|
|
245
|
+
twine check dist/*
|
|
246
|
+
|
|
247
|
+
# Upload to TestPyPI
|
|
248
|
+
twine upload --repository testpypi dist/*
|
|
249
|
+
|
|
250
|
+
# Upload to PyPI
|
|
251
|
+
twine upload dist/*
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Development
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
git clone https://github.com/placeholder/localist
|
|
260
|
+
cd localist
|
|
261
|
+
pip install -e ".[dev]"
|
|
262
|
+
pytest tests/ -v
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## License
|
|
268
|
+
|
|
269
|
+
MIT — see [LICENSE](LICENSE).
|
localist-0.1.0/README.md
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# localist
|
|
2
|
+
|
|
3
|
+
**Local agentic framework on Ollama** — give your local LLM sandboxed access to filesystem, web, shell, and OS tools via a ReAct reasoning loop.
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/localist/)
|
|
6
|
+
[](https://python.org)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## What is this?
|
|
12
|
+
|
|
13
|
+
`localist` is a Python library that wraps any [Ollama](https://ollama.ai)-served model and gives it the ability to autonomously:
|
|
14
|
+
|
|
15
|
+
- 📂 **Read / write / delete files** inside a sandboxed workspace
|
|
16
|
+
- 🌐 **Search the web** (DuckDuckGo, or Brave Search API)
|
|
17
|
+
- 🖥️ **Run shell commands** (behind a denylist + confirmation gate)
|
|
18
|
+
- 📋 **Use OS features** — clipboard, notifications, process management
|
|
19
|
+
|
|
20
|
+
It implements a **ReAct-style loop** (Reason → Act → Observe → repeat) and supports both models with native tool-calling (Qwen2.5, Llama 3.1+) and text-based tool-calling for any other model.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Install
|
|
28
|
+
pip install localist
|
|
29
|
+
|
|
30
|
+
# Make sure Ollama is running
|
|
31
|
+
ollama serve
|
|
32
|
+
ollama pull qwen2.5:7b
|
|
33
|
+
|
|
34
|
+
# Run a task
|
|
35
|
+
localist --task "Create a file called hello.txt with today's date, then list the workspace"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Core library + CLI
|
|
44
|
+
pip install localist
|
|
45
|
+
|
|
46
|
+
# With web UI (FastAPI + Uvicorn)
|
|
47
|
+
pip install "localist[ui]"
|
|
48
|
+
|
|
49
|
+
# Development
|
|
50
|
+
pip install "localist[dev]"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
### Python API
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from localist import Agent
|
|
61
|
+
|
|
62
|
+
agent = Agent(model="qwen2.5:7b", workspace_root="./workspace")
|
|
63
|
+
result = agent.run("Search for the latest Python release and save a summary to workspace/python_news.txt")
|
|
64
|
+
print(result)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Streaming events
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from localist import Agent
|
|
71
|
+
from localist.agent import ToolCallEvent, FinalAnswerEvent
|
|
72
|
+
|
|
73
|
+
agent = Agent(model="qwen2.5:7b")
|
|
74
|
+
|
|
75
|
+
for event in agent.stream("Summarise all .txt files in workspace"):
|
|
76
|
+
if isinstance(event, ToolCallEvent):
|
|
77
|
+
print(f" 🔧 Calling: {event.tool}({event.args})")
|
|
78
|
+
elif isinstance(event, FinalAnswerEvent):
|
|
79
|
+
print(f"\n✅ Answer:\n{event.content}")
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Custom tools
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from localist import Agent, register_tool
|
|
86
|
+
|
|
87
|
+
@register_tool
|
|
88
|
+
def count_words(text: str) -> int:
|
|
89
|
+
"""Count the number of words in a text string.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
text: The input text to count words in.
|
|
93
|
+
"""
|
|
94
|
+
return len(text.split())
|
|
95
|
+
|
|
96
|
+
agent = Agent(model="qwen2.5:7b")
|
|
97
|
+
result = agent.run("Count the words in 'The quick brown fox jumps over the lazy dog'")
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### CLI
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Single task
|
|
104
|
+
localist --task "Create a Python script that generates the Fibonacci sequence"
|
|
105
|
+
|
|
106
|
+
# Custom model and workspace
|
|
107
|
+
localist --task "..." --model llama3.1:8b --workspace ~/myproject
|
|
108
|
+
|
|
109
|
+
# Interactive REPL
|
|
110
|
+
localist --interactive
|
|
111
|
+
|
|
112
|
+
# Web UI (requires pip install localist[ui])
|
|
113
|
+
localist --ui
|
|
114
|
+
|
|
115
|
+
# List available Ollama models
|
|
116
|
+
localist --list-models
|
|
117
|
+
|
|
118
|
+
# Disable confirmation prompts (for scripts/automation)
|
|
119
|
+
localist --task "..." --no-confirm
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Tools
|
|
125
|
+
|
|
126
|
+
| Tool | Description | Confirmation required? |
|
|
127
|
+
|---|---|---|
|
|
128
|
+
| `file_read` | Read file contents | No |
|
|
129
|
+
| `file_write` | Create/overwrite a file | No (overwrite) |
|
|
130
|
+
| `file_append` | Append to a file | No |
|
|
131
|
+
| `file_delete` | Delete a file | **Yes** |
|
|
132
|
+
| `list_dir` | List directory contents | No |
|
|
133
|
+
| `web_search` | Search web (DuckDuckGo / Brave) | No |
|
|
134
|
+
| `web_fetch` | Fetch and extract text from URL | No |
|
|
135
|
+
| `shell_exec` | Run a shell command | **Yes** |
|
|
136
|
+
| `clipboard_get` | Read clipboard | No |
|
|
137
|
+
| `clipboard_set` | Write clipboard | No |
|
|
138
|
+
| `notify` | OS desktop notification | No |
|
|
139
|
+
| `process_list` | List running processes | No |
|
|
140
|
+
| `process_kill` | Terminate a process by PID | **Yes** |
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Configuration
|
|
145
|
+
|
|
146
|
+
Copy `.env.example` to `.env` and edit:
|
|
147
|
+
|
|
148
|
+
```env
|
|
149
|
+
LOCALIST_MODEL=qwen2.5:7b
|
|
150
|
+
LOCALIST_WORKSPACE_ROOT=./workspace
|
|
151
|
+
LOCALIST_MAX_ITERATIONS=20
|
|
152
|
+
LOCALIST_REQUIRE_CONFIRMATION=true
|
|
153
|
+
BRAVE_API_KEY= # optional — enables Brave Search API
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
All settings can also be passed programmatically:
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
from localist.config import LocalistConfig
|
|
160
|
+
from localist import Agent
|
|
161
|
+
|
|
162
|
+
cfg = LocalistConfig(model="llama3.1:8b", max_iterations=10, require_confirmation=False)
|
|
163
|
+
agent = Agent(config=cfg)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Safety
|
|
169
|
+
|
|
170
|
+
- **Filesystem jail**: every path is resolved against `workspace_root`; `..` traversal, symlink escapes, and absolute paths outside the workspace are rejected with `SandboxViolationError`.
|
|
171
|
+
- **Shell denylist**: `shell_exec` blocks `rm`, `sudo`, `curl`, `python`, shell interpreters, and other high-risk binaries. No `shell=True` anywhere.
|
|
172
|
+
- **Confirmation gate**: `file_delete`, `shell_exec`, and `process_kill` require explicit human approval (configurable).
|
|
173
|
+
- **Hard iteration cap**: the loop stops after `max_iterations` (default: 20) to prevent infinite loops.
|
|
174
|
+
- **Audit logging**: every tool call, result, and confirmation is written to `logs/audit_<date>.jsonl`.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Model Recommendations
|
|
179
|
+
|
|
180
|
+
| Model | Tool-calling | Notes |
|
|
181
|
+
|---|---|---|
|
|
182
|
+
| `qwen2.5:7b` / `qwen2.5:32b` | Native | Best balance of speed and reliability |
|
|
183
|
+
| `llama3.1:8b` / `llama3.3:70b` | Native | Strong general reasoning |
|
|
184
|
+
| `hermes3` | Native | Optimised for agentic tasks |
|
|
185
|
+
| `mistral-nemo` | Native | Fast, solid tool support |
|
|
186
|
+
| Any other model | Text protocol | Automatic fallback with JSON repair |
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Build and Publish
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# Install build tools
|
|
194
|
+
pip install build twine
|
|
195
|
+
|
|
196
|
+
# Build
|
|
197
|
+
python -m build
|
|
198
|
+
|
|
199
|
+
# Validate
|
|
200
|
+
twine check dist/*
|
|
201
|
+
|
|
202
|
+
# Upload to TestPyPI
|
|
203
|
+
twine upload --repository testpypi dist/*
|
|
204
|
+
|
|
205
|
+
# Upload to PyPI
|
|
206
|
+
twine upload dist/*
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Development
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
git clone https://github.com/placeholder/localist
|
|
215
|
+
cd localist
|
|
216
|
+
pip install -e ".[dev]"
|
|
217
|
+
pytest tests/ -v
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
MIT — see [LICENSE](LICENSE).
|