agentnova 0.2.1__tar.gz → 0.2.3__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.
- {agentnova-0.2.1 → agentnova-0.2.3}/PKG-INFO +34 -24
- {agentnova-0.2.1 → agentnova-0.2.3}/README.md +33 -23
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/__init__.py +3 -3
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/__main__.py +27 -27
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/bitnet_client.py +150 -150
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/cli.py +37 -13
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/core/agent.py +100 -41
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/core/math_prompts.py +396 -396
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/core/memory.py +191 -191
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/core/model_family_config.py +117 -18
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/core/ollama_client.py +552 -531
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/core/orchestrator.py +190 -190
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/core/orchestrator_enhanced.py +393 -393
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/core/tools.py +303 -303
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/examples/05_tool_tests.py +15 -5
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/examples/07_model_comparison.py +9 -2
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/examples/10_skills_demo.py +1 -1
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/examples/11_skill_creator_test.py +1 -1
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/examples/14_gsm8k_benchmark.py +1 -0
- agentnova-0.2.3/agentnova/examples/15_quick_diagnostic.py +241 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/model_discovery.py +341 -341
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/__init__.py +24 -24
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/loader.py +444 -444
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/tools/builtins.py +701 -692
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova.egg-info/PKG-INFO +34 -24
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova.egg-info/SOURCES.txt +1 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/pyproject.toml +1 -1
- {agentnova-0.2.1 → agentnova-0.2.3}/tests/test_acp_integration.py +217 -217
- {agentnova-0.2.1 → agentnova-0.2.3}/tests/test_acp_subagents.py +310 -310
- {agentnova-0.2.1 → agentnova-0.2.3}/LICENSE +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/acp_plugin.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/agent_mode.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/bitnet_setup.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/config.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/examples/00_backend_demo.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/examples/01_basic_agent.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/examples/02_tool_agent.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/examples/03_orchestrator.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/examples/04_comprehensive_test.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/examples/06_interactive_chat.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/examples/08_robust_comparison.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/examples/09_expanded_benchmark.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/examples/12_batch_operations.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/examples/13_shutdown_demo.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/shared_args.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/acp/SKILL.md +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/datetime/SKILL.md +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/skill-creator/SKILL.md +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/__init__.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/aggregate_benchmark.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/generate_report.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/improve_description.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/init_skill.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/package_skill.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/quick_validate.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/run_eval.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/run_loop.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/security_scan.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/test_package_skill.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/test_quick_validate.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/utils.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/validate.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/skills/web_search/SKILL.md +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova/tools/sandboxed_repl.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova.egg-info/dependency_links.txt +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova.egg-info/entry_points.txt +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova.egg-info/requires.txt +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/agentnova.egg-info/top_level.txt +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/localclaw/__init__.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/localclaw/__main__.py +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/setup.cfg +0 -0
- {agentnova-0.2.1 → agentnova-0.2.3}/tests/test_agent.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentnova
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: A minimal, hackable agentic framework for Ollama and BitNet - local-first AI agent toolkit
|
|
5
5
|
Author-email: VTSTech <veritas@vts-tech.org>
|
|
6
6
|
Maintainer-email: VTSTech <veritas@vts-tech.org>
|
|
@@ -34,7 +34,7 @@ Requires-Dist: black>=23.0; extra == "dev"
|
|
|
34
34
|
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
35
35
|
Dynamic: license-file
|
|
36
36
|
|
|
37
|
-
# ⚛️ AgentNova R02
|
|
37
|
+
# ⚛️ AgentNova R02.3
|
|
38
38
|
|
|
39
39
|
A minimal, hackable agentic framework engineered to run **entirely locally** with [Ollama](https://ollama.com) or [BitNet](https://github.com/microsoft/BitNet).
|
|
40
40
|
|
|
@@ -42,9 +42,10 @@ Inspired by the architecture of OpenClaw, rebuilt from scratch for local-first o
|
|
|
42
42
|
|
|
43
43
|
**Written by [VTSTech](https://www.vts-tech.org)** · [GitHub](https://github.com/VTSTech/AgentNova)
|
|
44
44
|
|
|
45
|
-
[](https://colab.research.google.com/github/VTSTech/AgentNova/blob/main/AgentNova.ipynb)
|
|
46
|
+
[](https://GitHub.com/VTSTech/AgentNova/commit/) [](https://GitHub.com/VTSTech/AgentNova/commit/)
|
|
47
|
+
[](https://pypi.org/project/agentnova/)
|
|
48
|
+
[](#license) [](https://python.org)
|
|
48
49
|
|
|
49
50
|
---
|
|
50
51
|
|
|
@@ -60,12 +61,9 @@ Inspired by the architecture of OpenClaw, rebuilt from scratch for local-first o
|
|
|
60
61
|
|
|
61
62
|
## Installation
|
|
62
63
|
|
|
63
|
-
### From PyPI (Recommended)
|
|
64
|
-
|
|
65
64
|
```bash
|
|
66
|
-
pip install agentnova
|
|
67
65
|
|
|
68
|
-
#
|
|
66
|
+
# Install from GitHub using pip:
|
|
69
67
|
pip install git+https://github.com/VTSTech/AgentNova.git
|
|
70
68
|
```
|
|
71
69
|
|
|
@@ -201,20 +199,31 @@ agentnova models --tool_support
|
|
|
201
199
|
|
|
202
200
|
### Performance by Tool Support
|
|
203
201
|
|
|
204
|
-
|
|
202
|
+
R02.3 benchmark results (15-test suite):
|
|
203
|
+
|
|
204
|
+
| Model | Params | Tool Support | Score | Time |
|
|
205
|
+
|-------|--------|--------------|-------|------|
|
|
206
|
+
| **`granite3.1-moe:1b`** | 1B MoE | react | **93% (14/15)** | 87.8s |
|
|
207
|
+
| **`llama3.2:1b`** | 1.2B | native | **87% (13/15)** | 150.2s |
|
|
208
|
+
| `dolphin3.0-qwen2.5:0.5b` | 500M | none | 73% (11/15) | 27.2s |
|
|
209
|
+
| `qwen3:0.6b` | 600M | react | 67% (10/15) | 189.3s |
|
|
210
|
+
| `qwen2.5-coder:0.5b` | 494M | react | 60% (9/15) | 133.1s |
|
|
211
|
+
|
|
212
|
+
**Quick Diagnostic (Test 15 - 5 questions, ~30s/model):**
|
|
205
213
|
|
|
206
|
-
| Model |
|
|
207
|
-
|
|
208
|
-
|
|
|
209
|
-
|
|
|
210
|
-
| `
|
|
211
|
-
| `
|
|
214
|
+
| Model | Score | Tool Support |
|
|
215
|
+
|-------|-------|--------------|
|
|
216
|
+
| **`qwen3.5:0.8b`** | **100%** | native |
|
|
217
|
+
| **`qwen2.5:0.5b`** | **100%** | react |
|
|
218
|
+
| `functiongemma:270m` | 80% | native |
|
|
219
|
+
| `granite4:350m` | 80% | native |
|
|
220
|
+
| `qwen3:0.6b` | 60% | react |
|
|
212
221
|
|
|
213
|
-
**Key improvements in
|
|
214
|
-
-
|
|
215
|
-
-
|
|
216
|
-
-
|
|
217
|
-
-
|
|
222
|
+
**Key improvements in R02.3**:
|
|
223
|
+
- **+13%** for granite3.1-moe:1b (80% → 93%) from few-shot fix
|
|
224
|
+
- **+20%** for llama3.2:1b (67% → 87%) from observation role fix
|
|
225
|
+
- **qwen3:0.6b restored** from 0% (broken) with `think=False` API fix
|
|
226
|
+
- **qwen3.5:0.8b** new sub-1B champion with 100% on quick diagnostic
|
|
218
227
|
|
|
219
228
|
---
|
|
220
229
|
|
|
@@ -265,7 +274,7 @@ Output shows:
|
|
|
265
274
|
- **Tool Support** - `✓ native`, `ReAct`, `○ none`, or `untested`
|
|
266
275
|
|
|
267
276
|
```
|
|
268
|
-
⚛️ AgentNova R02 Models
|
|
277
|
+
⚛️ AgentNova R02.3 Models
|
|
269
278
|
Model Family Context Tool Support
|
|
270
279
|
──────────────────────────────────────────────────────────────────────────────
|
|
271
280
|
gemma3:270m gemma3 32K ○ none
|
|
@@ -282,8 +291,9 @@ Output shows:
|
|
|
282
291
|
# List all available tests
|
|
283
292
|
agentnova test --list
|
|
284
293
|
|
|
285
|
-
#
|
|
286
|
-
agentnova test
|
|
294
|
+
# Quick diagnostic - 5 questions, ~30s/model (NEW in R02.3)
|
|
295
|
+
agentnova test 15 --model granite3.1-moe:1b
|
|
296
|
+
agentnova test 15 --model all --debug
|
|
287
297
|
|
|
288
298
|
# Run GSM8K benchmark (50 math questions)
|
|
289
299
|
agentnova test 14 --acp --timeout 6400
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ⚛️ AgentNova R02
|
|
1
|
+
# ⚛️ AgentNova R02.3
|
|
2
2
|
|
|
3
3
|
A minimal, hackable agentic framework engineered to run **entirely locally** with [Ollama](https://ollama.com) or [BitNet](https://github.com/microsoft/BitNet).
|
|
4
4
|
|
|
@@ -6,9 +6,10 @@ Inspired by the architecture of OpenClaw, rebuilt from scratch for local-first o
|
|
|
6
6
|
|
|
7
7
|
**Written by [VTSTech](https://www.vts-tech.org)** · [GitHub](https://github.com/VTSTech/AgentNova)
|
|
8
8
|
|
|
9
|
-
[](https://colab.research.google.com/github/VTSTech/AgentNova/blob/main/AgentNova.ipynb)
|
|
10
|
+
[](https://GitHub.com/VTSTech/AgentNova/commit/) [](https://GitHub.com/VTSTech/AgentNova/commit/)
|
|
11
|
+
[](https://pypi.org/project/agentnova/)
|
|
12
|
+
[](#license) [](https://python.org)
|
|
12
13
|
|
|
13
14
|
---
|
|
14
15
|
|
|
@@ -24,12 +25,9 @@ Inspired by the architecture of OpenClaw, rebuilt from scratch for local-first o
|
|
|
24
25
|
|
|
25
26
|
## Installation
|
|
26
27
|
|
|
27
|
-
### From PyPI (Recommended)
|
|
28
|
-
|
|
29
28
|
```bash
|
|
30
|
-
pip install agentnova
|
|
31
29
|
|
|
32
|
-
#
|
|
30
|
+
# Install from GitHub using pip:
|
|
33
31
|
pip install git+https://github.com/VTSTech/AgentNova.git
|
|
34
32
|
```
|
|
35
33
|
|
|
@@ -165,20 +163,31 @@ agentnova models --tool_support
|
|
|
165
163
|
|
|
166
164
|
### Performance by Tool Support
|
|
167
165
|
|
|
168
|
-
|
|
166
|
+
R02.3 benchmark results (15-test suite):
|
|
167
|
+
|
|
168
|
+
| Model | Params | Tool Support | Score | Time |
|
|
169
|
+
|-------|--------|--------------|-------|------|
|
|
170
|
+
| **`granite3.1-moe:1b`** | 1B MoE | react | **93% (14/15)** | 87.8s |
|
|
171
|
+
| **`llama3.2:1b`** | 1.2B | native | **87% (13/15)** | 150.2s |
|
|
172
|
+
| `dolphin3.0-qwen2.5:0.5b` | 500M | none | 73% (11/15) | 27.2s |
|
|
173
|
+
| `qwen3:0.6b` | 600M | react | 67% (10/15) | 189.3s |
|
|
174
|
+
| `qwen2.5-coder:0.5b` | 494M | react | 60% (9/15) | 133.1s |
|
|
175
|
+
|
|
176
|
+
**Quick Diagnostic (Test 15 - 5 questions, ~30s/model):**
|
|
169
177
|
|
|
170
|
-
| Model |
|
|
171
|
-
|
|
172
|
-
|
|
|
173
|
-
|
|
|
174
|
-
| `
|
|
175
|
-
| `
|
|
178
|
+
| Model | Score | Tool Support |
|
|
179
|
+
|-------|-------|--------------|
|
|
180
|
+
| **`qwen3.5:0.8b`** | **100%** | native |
|
|
181
|
+
| **`qwen2.5:0.5b`** | **100%** | react |
|
|
182
|
+
| `functiongemma:270m` | 80% | native |
|
|
183
|
+
| `granite4:350m` | 80% | native |
|
|
184
|
+
| `qwen3:0.6b` | 60% | react |
|
|
176
185
|
|
|
177
|
-
**Key improvements in
|
|
178
|
-
-
|
|
179
|
-
-
|
|
180
|
-
-
|
|
181
|
-
-
|
|
186
|
+
**Key improvements in R02.3**:
|
|
187
|
+
- **+13%** for granite3.1-moe:1b (80% → 93%) from few-shot fix
|
|
188
|
+
- **+20%** for llama3.2:1b (67% → 87%) from observation role fix
|
|
189
|
+
- **qwen3:0.6b restored** from 0% (broken) with `think=False` API fix
|
|
190
|
+
- **qwen3.5:0.8b** new sub-1B champion with 100% on quick diagnostic
|
|
182
191
|
|
|
183
192
|
---
|
|
184
193
|
|
|
@@ -229,7 +238,7 @@ Output shows:
|
|
|
229
238
|
- **Tool Support** - `✓ native`, `ReAct`, `○ none`, or `untested`
|
|
230
239
|
|
|
231
240
|
```
|
|
232
|
-
⚛️ AgentNova R02 Models
|
|
241
|
+
⚛️ AgentNova R02.3 Models
|
|
233
242
|
Model Family Context Tool Support
|
|
234
243
|
──────────────────────────────────────────────────────────────────────────────
|
|
235
244
|
gemma3:270m gemma3 32K ○ none
|
|
@@ -246,8 +255,9 @@ Output shows:
|
|
|
246
255
|
# List all available tests
|
|
247
256
|
agentnova test --list
|
|
248
257
|
|
|
249
|
-
#
|
|
250
|
-
agentnova test
|
|
258
|
+
# Quick diagnostic - 5 questions, ~30s/model (NEW in R02.3)
|
|
259
|
+
agentnova test 15 --model granite3.1-moe:1b
|
|
260
|
+
agentnova test 15 --model all --debug
|
|
251
261
|
|
|
252
262
|
# Run GSM8K benchmark (50 math questions)
|
|
253
263
|
agentnova test 14 --acp --timeout 6400
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
⚛️ AgentNova R02 - A minimal, hackable agentic framework for Ollama and BitNet
|
|
2
|
+
⚛️ AgentNova R02.3 - A minimal, hackable agentic framework for Ollama and BitNet
|
|
3
3
|
|
|
4
4
|
Written by VTSTech
|
|
5
5
|
https://www.vts-tech.org
|
|
@@ -184,7 +184,7 @@ __all__ = [
|
|
|
184
184
|
"create_file_write_action", "create_file_delete_action",
|
|
185
185
|
"create_mkdir_action", "create_shell_action",
|
|
186
186
|
"format_status", "format_progress",
|
|
187
|
-
# R02: Model Family Configuration
|
|
187
|
+
# R02.3: Model Family Configuration
|
|
188
188
|
"ModelFamilyConfig", "FAMILY_CONFIGS",
|
|
189
189
|
"get_family_config", "get_stop_tokens", "supports_tools",
|
|
190
190
|
"get_tool_format", "get_preferred_temperature", "should_use_few_shot",
|
|
@@ -204,7 +204,7 @@ __all__ = [
|
|
|
204
204
|
if _BITNET_AVAILABLE:
|
|
205
205
|
__all__.extend(["BitnetClient", "KNOWN_MODELS"])
|
|
206
206
|
|
|
207
|
-
__version__ = "0.2.
|
|
207
|
+
__version__ = "0.2.2"
|
|
208
208
|
__author__ = "VTSTech"
|
|
209
209
|
__author_email__ = "contact@vts-tech.org"
|
|
210
210
|
__url__ = "https://github.com/VTSTech/AgentNova"
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
⚛️ AgentNova R00 — Command Line Interface
|
|
4
|
-
|
|
5
|
-
Entry point for: python -m agentnova [command] [options]
|
|
6
|
-
|
|
7
|
-
Commands:
|
|
8
|
-
run Run the agent on a single prompt and exit
|
|
9
|
-
chat Interactive multi-turn conversation with memory
|
|
10
|
-
models List models available in Ollama
|
|
11
|
-
tools List available built-in tools
|
|
12
|
-
skills List available Agent Skills
|
|
13
|
-
|
|
14
|
-
Examples:
|
|
15
|
-
python -m agentnova run "What is the capital of France?"
|
|
16
|
-
python -m agentnova chat --model llama3.1:8b --tools calculator,shell
|
|
17
|
-
python -m agentnova models
|
|
18
|
-
python -m agentnova tools
|
|
19
|
-
python -m agentnova skills
|
|
20
|
-
|
|
21
|
-
Written by VTSTech · https://www.vts-tech.org · https://github.com/VTSTech/AgentNova
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
from agentnova.cli import main
|
|
25
|
-
|
|
26
|
-
if __name__ == "__main__":
|
|
27
|
-
main()
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
⚛️ AgentNova R00 — Command Line Interface
|
|
4
|
+
|
|
5
|
+
Entry point for: python -m agentnova [command] [options]
|
|
6
|
+
|
|
7
|
+
Commands:
|
|
8
|
+
run Run the agent on a single prompt and exit
|
|
9
|
+
chat Interactive multi-turn conversation with memory
|
|
10
|
+
models List models available in Ollama
|
|
11
|
+
tools List available built-in tools
|
|
12
|
+
skills List available Agent Skills
|
|
13
|
+
|
|
14
|
+
Examples:
|
|
15
|
+
python -m agentnova run "What is the capital of France?"
|
|
16
|
+
python -m agentnova chat --model llama3.1:8b --tools calculator,shell
|
|
17
|
+
python -m agentnova models
|
|
18
|
+
python -m agentnova tools
|
|
19
|
+
python -m agentnova skills
|
|
20
|
+
|
|
21
|
+
Written by VTSTech · https://www.vts-tech.org · https://github.com/VTSTech/AgentNova
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from agentnova.cli import main
|
|
25
|
+
|
|
26
|
+
if __name__ == "__main__":
|
|
27
|
+
main()
|
|
@@ -1,151 +1,151 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
⚛️ AgentNova R00 — BitnetClient
|
|
4
|
-
Drop-in replacement for OllamaClient that uses Microsoft's bitnet.cpp
|
|
5
|
-
(llama-server) as the inference backend instead of Ollama.
|
|
6
|
-
|
|
7
|
-
Architecture:
|
|
8
|
-
- Wraps bitnet.cpp's llama-server HTTP process
|
|
9
|
-
- Exposes the same interface as OllamaClient: chat(), list_models(),
|
|
10
|
-
model_supports_tools(), is_running()
|
|
11
|
-
- Normalises OpenAI-format responses → Ollama-format so agent.py is
|
|
12
|
-
completely unmodified
|
|
13
|
-
- Manages llama-server lifecycle (start/stop/health-check)
|
|
14
|
-
- Falls back gracefully to ReAct tool-calling (no native function
|
|
15
|
-
calling in current bitnet models)
|
|
16
|
-
|
|
17
|
-
Supported models (as of bitnet.cpp 2025):
|
|
18
|
-
- microsoft/BitNet-b1.58-2B-4T (~0.4 GB, recommended)
|
|
19
|
-
- 1bitLLM/bitnet_b1_58-3B (~0.7 GB)
|
|
20
|
-
- HF1BitLLM/Llama3-8B-1.58-100B-tokens
|
|
21
|
-
- tiiuae/Falcon3-1B-Instruct-1.58bit
|
|
22
|
-
- tiiuae/Falcon3-3B-Instruct-1.58bit
|
|
23
|
-
- tiiuae/Falcon3-7B-Instruct-1.58bit
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
import json
|
|
27
|
-
import urllib.request
|
|
28
|
-
from .config import BITNET_BASE_URL
|
|
29
|
-
|
|
30
|
-
# Known BitNet model identifiers
|
|
31
|
-
KNOWN_MODELS = [
|
|
32
|
-
"bitnet-b1.58-2b-4t",
|
|
33
|
-
"BitNet-b1.58-2B-4T",
|
|
34
|
-
"bitnet-b1.58-large",
|
|
35
|
-
]
|
|
36
|
-
|
|
37
|
-
class BitnetClient:
|
|
38
|
-
def __init__(self, base_url=None, timeout=120):
|
|
39
|
-
# Prioritize passed URL, fallback to config
|
|
40
|
-
self.base_url = base_url or BITNET_BASE_URL
|
|
41
|
-
self.timeout = timeout
|
|
42
|
-
|
|
43
|
-
def is_running(self) -> bool:
|
|
44
|
-
try:
|
|
45
|
-
with urllib.request.urlopen(f"{self.base_url}/health", timeout=2) as resp:
|
|
46
|
-
return resp.getcode() == 200
|
|
47
|
-
except:
|
|
48
|
-
return False
|
|
49
|
-
|
|
50
|
-
def list_models(self):
|
|
51
|
-
try:
|
|
52
|
-
with urllib.request.urlopen(f"{self.base_url}/v1/models", timeout=5) as resp:
|
|
53
|
-
if resp.getcode() == 200:
|
|
54
|
-
data = json.loads(resp.read().decode("utf-8"))
|
|
55
|
-
# Return the ID of the model(s), cleaned up to show just model folder/filename
|
|
56
|
-
models = []
|
|
57
|
-
for m in data.get('data', []):
|
|
58
|
-
model_id = m['id']
|
|
59
|
-
# Strip common prefixes to show just model_dir/filename.gguf
|
|
60
|
-
# e.g., /content/BitNet/models/BitNet-b1.58-2B-4T/bitnet_2b_i2_s.gguf
|
|
61
|
-
# -> BitNet-b1.58-2B-4T/bitnet_2b_i2_s.gguf
|
|
62
|
-
if '/models/' in model_id:
|
|
63
|
-
# Keep everything after /models/
|
|
64
|
-
model_id = model_id.split('/models/')[-1]
|
|
65
|
-
elif model_id.startswith('/'):
|
|
66
|
-
# Just keep last two path components
|
|
67
|
-
parts = model_id.strip('/').split('/')
|
|
68
|
-
if len(parts) >= 2:
|
|
69
|
-
model_id = '/'.join(parts[-2:])
|
|
70
|
-
models.append(model_id)
|
|
71
|
-
return models
|
|
72
|
-
except:
|
|
73
|
-
return []
|
|
74
|
-
|
|
75
|
-
def chat(
|
|
76
|
-
self,
|
|
77
|
-
model: str,
|
|
78
|
-
messages: list[dict],
|
|
79
|
-
options: dict | None = None,
|
|
80
|
-
stream: bool = False,
|
|
81
|
-
tools: list | None = None, # Signature fix for agent.py
|
|
82
|
-
**kwargs, # Catch-all for extra agent args
|
|
83
|
-
):
|
|
84
|
-
"""
|
|
85
|
-
Chat completion for BitNet.
|
|
86
|
-
|
|
87
|
-
Note: BitNet llama-server doesn't support streaming in the same way
|
|
88
|
-
as Ollama. When stream=True, this yields tokens from a streaming
|
|
89
|
-
response. Otherwise returns a complete response dict.
|
|
90
|
-
"""
|
|
91
|
-
url = f"{self.base_url}/v1/chat/completions"
|
|
92
|
-
|
|
93
|
-
data = {
|
|
94
|
-
"model": model,
|
|
95
|
-
"messages": messages,
|
|
96
|
-
"stream": stream,
|
|
97
|
-
"temperature": (options or {}).get("temperature", 0.7),
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
req = urllib.request.Request(
|
|
101
|
-
url,
|
|
102
|
-
data=json.dumps(data).encode("utf-8"),
|
|
103
|
-
headers={"Content-Type": "application/json"}
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
if stream:
|
|
107
|
-
# Return a generator for streaming
|
|
108
|
-
return self._stream_response(req, model)
|
|
109
|
-
else:
|
|
110
|
-
# Non-streaming: return complete response
|
|
111
|
-
with urllib.request.urlopen(req, timeout=self.timeout) as resp:
|
|
112
|
-
result = json.loads(resp.read().decode("utf-8"))
|
|
113
|
-
# Normalize OpenAI completion to Ollama format for the Agent
|
|
114
|
-
return {
|
|
115
|
-
"model": model,
|
|
116
|
-
"message": {
|
|
117
|
-
"role": "assistant",
|
|
118
|
-
"content": result["choices"][0]["message"]["content"]
|
|
119
|
-
},
|
|
120
|
-
"done": True
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
def _stream_response(self, req, model):
|
|
124
|
-
"""
|
|
125
|
-
Handle SSE streaming response from BitNet server.
|
|
126
|
-
Yields tokens one at a time.
|
|
127
|
-
"""
|
|
128
|
-
with urllib.request.urlopen(req, timeout=self.timeout) as resp:
|
|
129
|
-
buffer = ""
|
|
130
|
-
for line in resp:
|
|
131
|
-
line = line.decode("utf-8")
|
|
132
|
-
if line.startswith("data: "):
|
|
133
|
-
data_str = line[6:].strip()
|
|
134
|
-
if data_str == "[DONE]":
|
|
135
|
-
break
|
|
136
|
-
try:
|
|
137
|
-
chunk = json.loads(data_str)
|
|
138
|
-
if "choices" in chunk and len(chunk["choices"]) > 0:
|
|
139
|
-
delta = chunk["choices"][0].get("delta", {})
|
|
140
|
-
content = delta.get("content", "")
|
|
141
|
-
if content:
|
|
142
|
-
yield content
|
|
143
|
-
except json.JSONDecodeError:
|
|
144
|
-
continue
|
|
145
|
-
|
|
146
|
-
def model_supports_tools(self, model: str) -> bool:
|
|
147
|
-
return False # BitNet models require ReAct fallback in Agent.py
|
|
148
|
-
|
|
149
|
-
def supports_streaming(self) -> bool:
|
|
150
|
-
"""Return True if this client supports streaming."""
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
⚛️ AgentNova R00 — BitnetClient
|
|
4
|
+
Drop-in replacement for OllamaClient that uses Microsoft's bitnet.cpp
|
|
5
|
+
(llama-server) as the inference backend instead of Ollama.
|
|
6
|
+
|
|
7
|
+
Architecture:
|
|
8
|
+
- Wraps bitnet.cpp's llama-server HTTP process
|
|
9
|
+
- Exposes the same interface as OllamaClient: chat(), list_models(),
|
|
10
|
+
model_supports_tools(), is_running()
|
|
11
|
+
- Normalises OpenAI-format responses → Ollama-format so agent.py is
|
|
12
|
+
completely unmodified
|
|
13
|
+
- Manages llama-server lifecycle (start/stop/health-check)
|
|
14
|
+
- Falls back gracefully to ReAct tool-calling (no native function
|
|
15
|
+
calling in current bitnet models)
|
|
16
|
+
|
|
17
|
+
Supported models (as of bitnet.cpp 2025):
|
|
18
|
+
- microsoft/BitNet-b1.58-2B-4T (~0.4 GB, recommended)
|
|
19
|
+
- 1bitLLM/bitnet_b1_58-3B (~0.7 GB)
|
|
20
|
+
- HF1BitLLM/Llama3-8B-1.58-100B-tokens
|
|
21
|
+
- tiiuae/Falcon3-1B-Instruct-1.58bit
|
|
22
|
+
- tiiuae/Falcon3-3B-Instruct-1.58bit
|
|
23
|
+
- tiiuae/Falcon3-7B-Instruct-1.58bit
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import json
|
|
27
|
+
import urllib.request
|
|
28
|
+
from .config import BITNET_BASE_URL
|
|
29
|
+
|
|
30
|
+
# Known BitNet model identifiers
|
|
31
|
+
KNOWN_MODELS = [
|
|
32
|
+
"bitnet-b1.58-2b-4t",
|
|
33
|
+
"BitNet-b1.58-2B-4T",
|
|
34
|
+
"bitnet-b1.58-large",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
class BitnetClient:
|
|
38
|
+
def __init__(self, base_url=None, timeout=120):
|
|
39
|
+
# Prioritize passed URL, fallback to config
|
|
40
|
+
self.base_url = base_url or BITNET_BASE_URL
|
|
41
|
+
self.timeout = timeout
|
|
42
|
+
|
|
43
|
+
def is_running(self) -> bool:
|
|
44
|
+
try:
|
|
45
|
+
with urllib.request.urlopen(f"{self.base_url}/health", timeout=2) as resp:
|
|
46
|
+
return resp.getcode() == 200
|
|
47
|
+
except:
|
|
48
|
+
return False
|
|
49
|
+
|
|
50
|
+
def list_models(self):
|
|
51
|
+
try:
|
|
52
|
+
with urllib.request.urlopen(f"{self.base_url}/v1/models", timeout=5) as resp:
|
|
53
|
+
if resp.getcode() == 200:
|
|
54
|
+
data = json.loads(resp.read().decode("utf-8"))
|
|
55
|
+
# Return the ID of the model(s), cleaned up to show just model folder/filename
|
|
56
|
+
models = []
|
|
57
|
+
for m in data.get('data', []):
|
|
58
|
+
model_id = m['id']
|
|
59
|
+
# Strip common prefixes to show just model_dir/filename.gguf
|
|
60
|
+
# e.g., /content/BitNet/models/BitNet-b1.58-2B-4T/bitnet_2b_i2_s.gguf
|
|
61
|
+
# -> BitNet-b1.58-2B-4T/bitnet_2b_i2_s.gguf
|
|
62
|
+
if '/models/' in model_id:
|
|
63
|
+
# Keep everything after /models/
|
|
64
|
+
model_id = model_id.split('/models/')[-1]
|
|
65
|
+
elif model_id.startswith('/'):
|
|
66
|
+
# Just keep last two path components
|
|
67
|
+
parts = model_id.strip('/').split('/')
|
|
68
|
+
if len(parts) >= 2:
|
|
69
|
+
model_id = '/'.join(parts[-2:])
|
|
70
|
+
models.append(model_id)
|
|
71
|
+
return models
|
|
72
|
+
except:
|
|
73
|
+
return []
|
|
74
|
+
|
|
75
|
+
def chat(
|
|
76
|
+
self,
|
|
77
|
+
model: str,
|
|
78
|
+
messages: list[dict],
|
|
79
|
+
options: dict | None = None,
|
|
80
|
+
stream: bool = False,
|
|
81
|
+
tools: list | None = None, # Signature fix for agent.py
|
|
82
|
+
**kwargs, # Catch-all for extra agent args
|
|
83
|
+
):
|
|
84
|
+
"""
|
|
85
|
+
Chat completion for BitNet.
|
|
86
|
+
|
|
87
|
+
Note: BitNet llama-server doesn't support streaming in the same way
|
|
88
|
+
as Ollama. When stream=True, this yields tokens from a streaming
|
|
89
|
+
response. Otherwise returns a complete response dict.
|
|
90
|
+
"""
|
|
91
|
+
url = f"{self.base_url}/v1/chat/completions"
|
|
92
|
+
|
|
93
|
+
data = {
|
|
94
|
+
"model": model,
|
|
95
|
+
"messages": messages,
|
|
96
|
+
"stream": stream,
|
|
97
|
+
"temperature": (options or {}).get("temperature", 0.7),
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
req = urllib.request.Request(
|
|
101
|
+
url,
|
|
102
|
+
data=json.dumps(data).encode("utf-8"),
|
|
103
|
+
headers={"Content-Type": "application/json"}
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
if stream:
|
|
107
|
+
# Return a generator for streaming
|
|
108
|
+
return self._stream_response(req, model)
|
|
109
|
+
else:
|
|
110
|
+
# Non-streaming: return complete response
|
|
111
|
+
with urllib.request.urlopen(req, timeout=self.timeout) as resp:
|
|
112
|
+
result = json.loads(resp.read().decode("utf-8"))
|
|
113
|
+
# Normalize OpenAI completion to Ollama format for the Agent
|
|
114
|
+
return {
|
|
115
|
+
"model": model,
|
|
116
|
+
"message": {
|
|
117
|
+
"role": "assistant",
|
|
118
|
+
"content": result["choices"][0]["message"]["content"]
|
|
119
|
+
},
|
|
120
|
+
"done": True
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
def _stream_response(self, req, model):
|
|
124
|
+
"""
|
|
125
|
+
Handle SSE streaming response from BitNet server.
|
|
126
|
+
Yields tokens one at a time.
|
|
127
|
+
"""
|
|
128
|
+
with urllib.request.urlopen(req, timeout=self.timeout) as resp:
|
|
129
|
+
buffer = ""
|
|
130
|
+
for line in resp:
|
|
131
|
+
line = line.decode("utf-8")
|
|
132
|
+
if line.startswith("data: "):
|
|
133
|
+
data_str = line[6:].strip()
|
|
134
|
+
if data_str == "[DONE]":
|
|
135
|
+
break
|
|
136
|
+
try:
|
|
137
|
+
chunk = json.loads(data_str)
|
|
138
|
+
if "choices" in chunk and len(chunk["choices"]) > 0:
|
|
139
|
+
delta = chunk["choices"][0].get("delta", {})
|
|
140
|
+
content = delta.get("content", "")
|
|
141
|
+
if content:
|
|
142
|
+
yield content
|
|
143
|
+
except json.JSONDecodeError:
|
|
144
|
+
continue
|
|
145
|
+
|
|
146
|
+
def model_supports_tools(self, model: str) -> bool:
|
|
147
|
+
return False # BitNet models require ReAct fallback in Agent.py
|
|
148
|
+
|
|
149
|
+
def supports_streaming(self) -> bool:
|
|
150
|
+
"""Return True if this client supports streaming."""
|
|
151
151
|
return True
|