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.
Files changed (72) hide show
  1. {agentnova-0.2.2 → agentnova-0.2.4}/PKG-INFO +35 -17
  2. {agentnova-0.2.2 → agentnova-0.2.4}/README.md +34 -16
  3. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/__init__.py +4 -4
  4. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/__main__.py +27 -27
  5. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/bitnet_client.py +150 -150
  6. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/cli.py +12 -11
  7. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/core/agent.py +47 -24
  8. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/core/math_prompts.py +396 -396
  9. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/core/memory.py +191 -191
  10. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/core/model_family_config.py +62 -7
  11. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/core/ollama_client.py +552 -542
  12. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/core/orchestrator.py +190 -190
  13. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/core/orchestrator_enhanced.py +393 -393
  14. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/core/tools.py +303 -303
  15. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/10_skills_demo.py +1 -1
  16. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/11_skill_creator_test.py +1 -1
  17. agentnova-0.2.4/agentnova/examples/15_quick_diagnostic.py +296 -0
  18. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/model_discovery.py +341 -341
  19. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/__init__.py +24 -24
  20. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/loader.py +444 -444
  21. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/tools/builtins.py +701 -701
  22. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova.egg-info/PKG-INFO +35 -17
  23. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova.egg-info/SOURCES.txt +1 -0
  24. {agentnova-0.2.2 → agentnova-0.2.4}/pyproject.toml +1 -1
  25. {agentnova-0.2.2 → agentnova-0.2.4}/tests/test_acp_integration.py +217 -217
  26. {agentnova-0.2.2 → agentnova-0.2.4}/tests/test_acp_subagents.py +310 -310
  27. {agentnova-0.2.2 → agentnova-0.2.4}/LICENSE +0 -0
  28. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/acp_plugin.py +0 -0
  29. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/agent_mode.py +0 -0
  30. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/bitnet_setup.py +0 -0
  31. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/config.py +0 -0
  32. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/00_backend_demo.py +0 -0
  33. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/01_basic_agent.py +0 -0
  34. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/02_tool_agent.py +0 -0
  35. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/03_orchestrator.py +0 -0
  36. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/04_comprehensive_test.py +0 -0
  37. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/05_tool_tests.py +0 -0
  38. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/06_interactive_chat.py +0 -0
  39. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/07_model_comparison.py +0 -0
  40. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/08_robust_comparison.py +0 -0
  41. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/09_expanded_benchmark.py +0 -0
  42. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/12_batch_operations.py +0 -0
  43. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/13_shutdown_demo.py +0 -0
  44. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/examples/14_gsm8k_benchmark.py +0 -0
  45. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/shared_args.py +0 -0
  46. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/acp/SKILL.md +0 -0
  47. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/datetime/SKILL.md +0 -0
  48. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/SKILL.md +0 -0
  49. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/__init__.py +0 -0
  50. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/aggregate_benchmark.py +0 -0
  51. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/generate_report.py +0 -0
  52. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/improve_description.py +0 -0
  53. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/init_skill.py +0 -0
  54. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/package_skill.py +0 -0
  55. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/quick_validate.py +0 -0
  56. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/run_eval.py +0 -0
  57. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/run_loop.py +0 -0
  58. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/security_scan.py +0 -0
  59. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/test_package_skill.py +0 -0
  60. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/test_quick_validate.py +0 -0
  61. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/utils.py +0 -0
  62. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/skill-creator/scripts/validate.py +0 -0
  63. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/skills/web_search/SKILL.md +0 -0
  64. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova/tools/sandboxed_repl.py +0 -0
  65. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova.egg-info/dependency_links.txt +0 -0
  66. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova.egg-info/entry_points.txt +0 -0
  67. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova.egg-info/requires.txt +0 -0
  68. {agentnova-0.2.2 → agentnova-0.2.4}/agentnova.egg-info/top_level.txt +0 -0
  69. {agentnova-0.2.2 → agentnova-0.2.4}/localclaw/__init__.py +0 -0
  70. {agentnova-0.2.2 → agentnova-0.2.4}/localclaw/__main__.py +0 -0
  71. {agentnova-0.2.2 → agentnova-0.2.4}/setup.cfg +0 -0
  72. {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.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
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/VTSTech/AgentNova/blob/main/AgentNova.ipynb)
45
46
  [![GitHub commits](https://badgen.net/github/commits/VTSTech/AgentNova)](https://GitHub.com/VTSTech/AgentNova/commit/) [![GitHub latest commit](https://badgen.net/github/last-commit/VTSTech/AgentNova)](https://GitHub.com/VTSTech/AgentNova/commit/)
47
+
48
+ [![pip - agentnova](https://img.shields.io/badge/pip-agentnova-2ea44f?logo=PyPi)](https://pypi.org/project/agentnova/) [![PyPI version fury.io](https://badge.fury.io/py/agentnova.svg)](https://pypi.python.org/pypi/agentnova/) [![PyPI download month](https://img.shields.io/pypi/dm/agentnova.svg)](https://pypi.python.org/pypi/agentnova/) [![PyPI download day](https://img.shields.io/pypi/dd/agentnova.svg)](https://pypi.python.org/pypi/agentnova/)
49
+
50
+ [![License](https://img.shields.io/badge/License-MIT-blue)](#license) [![Go to Python website](https://img.shields.io/badge/dynamic/toml?url=https%3A%2F%2Fraw.githubusercontent.com%2FVTSTech%2FAgentNova%2Frefs%2Fheads%2Fmain%2Fpyproject.toml&query=project.requires-python&label=python&logo=python&logoColor=white)](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
- Recent test results with native tool synthesis:
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 | Params | Tool Support | Calculator | Shell | Python |
201
- |-------|--------|--------------|------------|-------|--------|
202
- | `qwen2.5:0.5b` | 494M | native | **100%** | **100%** | **100%** |
203
- | `qwen2.5-coder:0.5b` | 494M | ReAct | **100%** | **100%** | **100%** |
204
- | `granite4:350m` | 350M | native | ~90% | ✅ | ✅ |
205
- | `gemma3:270m` | 270M | none | **64%** | N/A | N/A |
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 R01**:
208
- - Native tool synthesis extracts expressions from natural language
209
- - Two-tier retry: hintsynthesize (bypasses confused models)
210
- - Bare expression wrapping: `2**20` `print(2**20)`
211
- - Hallucinated mention detection for models that talk about tools but don't call them
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
- # Run a quick test suite
280
- agentnova test quick
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
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/VTSTech/AgentNova/blob/main/AgentNova.ipynb)
9
10
  [![GitHub commits](https://badgen.net/github/commits/VTSTech/AgentNova)](https://GitHub.com/VTSTech/AgentNova/commit/) [![GitHub latest commit](https://badgen.net/github/last-commit/VTSTech/AgentNova)](https://GitHub.com/VTSTech/AgentNova/commit/)
11
+
12
+ [![pip - agentnova](https://img.shields.io/badge/pip-agentnova-2ea44f?logo=PyPi)](https://pypi.org/project/agentnova/) [![PyPI version fury.io](https://badge.fury.io/py/agentnova.svg)](https://pypi.python.org/pypi/agentnova/) [![PyPI download month](https://img.shields.io/pypi/dm/agentnova.svg)](https://pypi.python.org/pypi/agentnova/) [![PyPI download day](https://img.shields.io/pypi/dd/agentnova.svg)](https://pypi.python.org/pypi/agentnova/)
13
+
14
+ [![License](https://img.shields.io/badge/License-MIT-blue)](#license) [![Go to Python website](https://img.shields.io/badge/dynamic/toml?url=https%3A%2F%2Fraw.githubusercontent.com%2FVTSTech%2FAgentNova%2Frefs%2Fheads%2Fmain%2Fpyproject.toml&query=project.requires-python&label=python&logo=python&logoColor=white)](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
- Recent test results with native tool synthesis:
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 | Params | Tool Support | Calculator | Shell | Python |
165
- |-------|--------|--------------|------------|-------|--------|
166
- | `qwen2.5:0.5b` | 494M | native | **100%** | **100%** | **100%** |
167
- | `qwen2.5-coder:0.5b` | 494M | ReAct | **100%** | **100%** | **100%** |
168
- | `granite4:350m` | 350M | native | ~90% | ✅ | ✅ |
169
- | `gemma3:270m` | 270M | none | **64%** | N/A | N/A |
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 R01**:
172
- - Native tool synthesis extracts expressions from natural language
173
- - Two-tier retry: hintsynthesize (bypasses confused models)
174
- - Bare expression wrapping: `2**20` `print(2**20)`
175
- - Hallucinated mention detection for models that talk about tools but don't call them
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
- # Run a quick test suite
244
- agentnova test quick
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.2"
207
+ __version__ = "0.2.4"
208
208
  __author__ = "VTSTech"
209
- __author_email__ = "contact@vts-tech.org"
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