agentnova 0.2.2__tar.gz → 0.2.4__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.2 → agentnova-0.2.4}/PKG-INFO +35 -17
- {agentnova-0.2.2 → agentnova-0.2.4}/README.md +34 -16
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/__init__.py +4 -4
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/__main__.py +27 -27
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/bitnet_client.py +150 -150
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/cli.py +12 -11
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/core/agent.py +47 -24
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/core/math_prompts.py +396 -396
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/core/memory.py +191 -191
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/core/model_family_config.py +62 -7
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/core/ollama_client.py +552 -542
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/core/orchestrator.py +190 -190
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/core/orchestrator_enhanced.py +393 -393
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/core/tools.py +303 -303
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/10_skills_demo.py +1 -1
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/11_skill_creator_test.py +1 -1
- agentnova-0.2.4/agentnova/examples/15_quick_diagnostic.py +296 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/model_discovery.py +341 -341
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/__init__.py +24 -24
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/loader.py +444 -444
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/tools/builtins.py +701 -701
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova.egg-info/PKG-INFO +35 -17
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova.egg-info/SOURCES.txt +1 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/pyproject.toml +1 -1
- {agentnova-0.2.2 → agentnova-0.2.4}/tests/test_acp_integration.py +217 -217
- {agentnova-0.2.2 → agentnova-0.2.4}/tests/test_acp_subagents.py +310 -310
- {agentnova-0.2.2 → agentnova-0.2.4}/LICENSE +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/acp_plugin.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/agent_mode.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/bitnet_setup.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/config.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/00_backend_demo.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/01_basic_agent.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/02_tool_agent.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/03_orchestrator.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/04_comprehensive_test.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/05_tool_tests.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/06_interactive_chat.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/07_model_comparison.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/08_robust_comparison.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/09_expanded_benchmark.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/12_batch_operations.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/13_shutdown_demo.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/14_gsm8k_benchmark.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/shared_args.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/acp/SKILL.md +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/datetime/SKILL.md +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/SKILL.md +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/__init__.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/aggregate_benchmark.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/generate_report.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/improve_description.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/init_skill.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/package_skill.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/quick_validate.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/run_eval.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/run_loop.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/security_scan.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/test_package_skill.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/test_quick_validate.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/utils.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/validate.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/web_search/SKILL.md +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/tools/sandboxed_repl.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova.egg-info/dependency_links.txt +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova.egg-info/entry_points.txt +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova.egg-info/requires.txt +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/agentnova.egg-info/top_level.txt +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/localclaw/__init__.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/localclaw/__main__.py +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/setup.cfg +0 -0
- {agentnova-0.2.2 → agentnova-0.2.4}/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.4
|
|
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.4
|
|
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,7 +42,13 @@ 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)
|
|
45
46
|
[](https://GitHub.com/VTSTech/AgentNova/commit/) [](https://GitHub.com/VTSTech/AgentNova/commit/)
|
|
47
|
+
|
|
48
|
+
[](https://pypi.org/project/agentnova/) [](https://pypi.python.org/pypi/agentnova/) [](https://pypi.python.org/pypi/agentnova/) [](https://pypi.python.org/pypi/agentnova/)
|
|
49
|
+
|
|
50
|
+
[](#license) [](https://python.org)
|
|
51
|
+
|
|
46
52
|
---
|
|
47
53
|
|
|
48
54
|
## 📚 Documentation
|
|
@@ -195,20 +201,31 @@ agentnova models --tool_support
|
|
|
195
201
|
|
|
196
202
|
### Performance by Tool Support
|
|
197
203
|
|
|
198
|
-
|
|
204
|
+
R02.3 benchmark results (15-test suite):
|
|
205
|
+
|
|
206
|
+
| Model | Params | Tool Support | Score | Time |
|
|
207
|
+
|-------|--------|--------------|-------|------|
|
|
208
|
+
| **`granite3.1-moe:1b`** | 1B MoE | react | **93% (14/15)** | 87.8s |
|
|
209
|
+
| **`llama3.2:1b`** | 1.2B | native | **87% (13/15)** | 150.2s |
|
|
210
|
+
| `dolphin3.0-qwen2.5:0.5b` | 500M | none | 73% (11/15) | 27.2s |
|
|
211
|
+
| `qwen3:0.6b` | 600M | react | 67% (10/15) | 189.3s |
|
|
212
|
+
| `qwen2.5-coder:0.5b` | 494M | react | 60% (9/15) | 133.1s |
|
|
213
|
+
|
|
214
|
+
**Quick Diagnostic (Test 15 - 5 questions, ~30s/model):**
|
|
199
215
|
|
|
200
|
-
| Model |
|
|
201
|
-
|
|
202
|
-
|
|
|
203
|
-
|
|
|
204
|
-
| `
|
|
205
|
-
| `
|
|
216
|
+
| Model | Score | Tool Support |
|
|
217
|
+
|-------|-------|--------------|
|
|
218
|
+
| **`qwen3.5:0.8b`** | **100%** | native |
|
|
219
|
+
| **`qwen2.5:0.5b`** | **100%** | react |
|
|
220
|
+
| `functiongemma:270m` | 80% | native |
|
|
221
|
+
| `granite4:350m` | 80% | native |
|
|
222
|
+
| `qwen3:0.6b` | 60% | react |
|
|
206
223
|
|
|
207
|
-
**Key improvements in
|
|
208
|
-
-
|
|
209
|
-
-
|
|
210
|
-
-
|
|
211
|
-
-
|
|
224
|
+
**Key improvements in R02.3**:
|
|
225
|
+
- **+13%** for granite3.1-moe:1b (80% → 93%) from few-shot fix
|
|
226
|
+
- **+20%** for llama3.2:1b (67% → 87%) from observation role fix
|
|
227
|
+
- **qwen3:0.6b restored** from 0% (broken) with `think=False` API fix
|
|
228
|
+
- **qwen3.5:0.8b** new sub-1B champion with 100% on quick diagnostic
|
|
212
229
|
|
|
213
230
|
---
|
|
214
231
|
|
|
@@ -259,7 +276,7 @@ Output shows:
|
|
|
259
276
|
- **Tool Support** - `✓ native`, `ReAct`, `○ none`, or `untested`
|
|
260
277
|
|
|
261
278
|
```
|
|
262
|
-
⚛️ AgentNova R02 Models
|
|
279
|
+
⚛️ AgentNova R02.3 Models
|
|
263
280
|
Model Family Context Tool Support
|
|
264
281
|
──────────────────────────────────────────────────────────────────────────────
|
|
265
282
|
gemma3:270m gemma3 32K ○ none
|
|
@@ -276,8 +293,9 @@ Output shows:
|
|
|
276
293
|
# List all available tests
|
|
277
294
|
agentnova test --list
|
|
278
295
|
|
|
279
|
-
#
|
|
280
|
-
agentnova test
|
|
296
|
+
# Quick diagnostic - 5 questions, ~30s/model (NEW in R02.3)
|
|
297
|
+
agentnova test 15 --model granite3.1-moe:1b
|
|
298
|
+
agentnova test 15 --model all --debug
|
|
281
299
|
|
|
282
300
|
# Run GSM8K benchmark (50 math questions)
|
|
283
301
|
agentnova test 14 --acp --timeout 6400
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ⚛️ AgentNova R02
|
|
1
|
+
# ⚛️ AgentNova R02.4
|
|
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,7 +6,13 @@ 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)
|
|
9
10
|
[](https://GitHub.com/VTSTech/AgentNova/commit/) [](https://GitHub.com/VTSTech/AgentNova/commit/)
|
|
11
|
+
|
|
12
|
+
[](https://pypi.org/project/agentnova/) [](https://pypi.python.org/pypi/agentnova/) [](https://pypi.python.org/pypi/agentnova/) [](https://pypi.python.org/pypi/agentnova/)
|
|
13
|
+
|
|
14
|
+
[](#license) [](https://python.org)
|
|
15
|
+
|
|
10
16
|
---
|
|
11
17
|
|
|
12
18
|
## 📚 Documentation
|
|
@@ -159,20 +165,31 @@ agentnova models --tool_support
|
|
|
159
165
|
|
|
160
166
|
### Performance by Tool Support
|
|
161
167
|
|
|
162
|
-
|
|
168
|
+
R02.3 benchmark results (15-test suite):
|
|
169
|
+
|
|
170
|
+
| Model | Params | Tool Support | Score | Time |
|
|
171
|
+
|-------|--------|--------------|-------|------|
|
|
172
|
+
| **`granite3.1-moe:1b`** | 1B MoE | react | **93% (14/15)** | 87.8s |
|
|
173
|
+
| **`llama3.2:1b`** | 1.2B | native | **87% (13/15)** | 150.2s |
|
|
174
|
+
| `dolphin3.0-qwen2.5:0.5b` | 500M | none | 73% (11/15) | 27.2s |
|
|
175
|
+
| `qwen3:0.6b` | 600M | react | 67% (10/15) | 189.3s |
|
|
176
|
+
| `qwen2.5-coder:0.5b` | 494M | react | 60% (9/15) | 133.1s |
|
|
177
|
+
|
|
178
|
+
**Quick Diagnostic (Test 15 - 5 questions, ~30s/model):**
|
|
163
179
|
|
|
164
|
-
| Model |
|
|
165
|
-
|
|
166
|
-
|
|
|
167
|
-
|
|
|
168
|
-
| `
|
|
169
|
-
| `
|
|
180
|
+
| Model | Score | Tool Support |
|
|
181
|
+
|-------|-------|--------------|
|
|
182
|
+
| **`qwen3.5:0.8b`** | **100%** | native |
|
|
183
|
+
| **`qwen2.5:0.5b`** | **100%** | react |
|
|
184
|
+
| `functiongemma:270m` | 80% | native |
|
|
185
|
+
| `granite4:350m` | 80% | native |
|
|
186
|
+
| `qwen3:0.6b` | 60% | react |
|
|
170
187
|
|
|
171
|
-
**Key improvements in
|
|
172
|
-
-
|
|
173
|
-
-
|
|
174
|
-
-
|
|
175
|
-
-
|
|
188
|
+
**Key improvements in R02.3**:
|
|
189
|
+
- **+13%** for granite3.1-moe:1b (80% → 93%) from few-shot fix
|
|
190
|
+
- **+20%** for llama3.2:1b (67% → 87%) from observation role fix
|
|
191
|
+
- **qwen3:0.6b restored** from 0% (broken) with `think=False` API fix
|
|
192
|
+
- **qwen3.5:0.8b** new sub-1B champion with 100% on quick diagnostic
|
|
176
193
|
|
|
177
194
|
---
|
|
178
195
|
|
|
@@ -223,7 +240,7 @@ Output shows:
|
|
|
223
240
|
- **Tool Support** - `✓ native`, `ReAct`, `○ none`, or `untested`
|
|
224
241
|
|
|
225
242
|
```
|
|
226
|
-
⚛️ AgentNova R02 Models
|
|
243
|
+
⚛️ AgentNova R02.3 Models
|
|
227
244
|
Model Family Context Tool Support
|
|
228
245
|
──────────────────────────────────────────────────────────────────────────────
|
|
229
246
|
gemma3:270m gemma3 32K ○ none
|
|
@@ -240,8 +257,9 @@ Output shows:
|
|
|
240
257
|
# List all available tests
|
|
241
258
|
agentnova test --list
|
|
242
259
|
|
|
243
|
-
#
|
|
244
|
-
agentnova test
|
|
260
|
+
# Quick diagnostic - 5 questions, ~30s/model (NEW in R02.3)
|
|
261
|
+
agentnova test 15 --model granite3.1-moe:1b
|
|
262
|
+
agentnova test 15 --model all --debug
|
|
245
263
|
|
|
246
264
|
# Run GSM8K benchmark (50 math questions)
|
|
247
265
|
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,8 +204,8 @@ __all__ = [
|
|
|
204
204
|
if _BITNET_AVAILABLE:
|
|
205
205
|
__all__.extend(["BitnetClient", "KNOWN_MODELS"])
|
|
206
206
|
|
|
207
|
-
__version__ = "0.2.
|
|
207
|
+
__version__ = "0.2.4"
|
|
208
208
|
__author__ = "VTSTech"
|
|
209
|
-
__author_email__ = "
|
|
209
|
+
__author_email__ = "veritas@vts-tech.org"
|
|
210
210
|
__url__ = "https://github.com/VTSTech/AgentNova"
|
|
211
211
|
__website__ = "https://www.vts-tech.org"
|
|
@@ -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
|