agentnova 0.2.2__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.
Files changed (72) hide show
  1. {agentnova-0.2.2 → agentnova-0.2.3}/PKG-INFO +33 -17
  2. {agentnova-0.2.2 → agentnova-0.2.3}/README.md +32 -16
  3. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/__init__.py +2 -2
  4. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/__main__.py +27 -27
  5. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/bitnet_client.py +150 -150
  6. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/cli.py +12 -11
  7. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/core/agent.py +11 -4
  8. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/core/math_prompts.py +396 -396
  9. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/core/memory.py +191 -191
  10. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/core/model_family_config.py +57 -7
  11. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/core/ollama_client.py +552 -542
  12. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/core/orchestrator.py +190 -190
  13. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/core/orchestrator_enhanced.py +393 -393
  14. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/core/tools.py +303 -303
  15. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/examples/10_skills_demo.py +1 -1
  16. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/examples/11_skill_creator_test.py +1 -1
  17. agentnova-0.2.3/agentnova/examples/15_quick_diagnostic.py +241 -0
  18. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/model_discovery.py +341 -341
  19. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/__init__.py +24 -24
  20. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/loader.py +444 -444
  21. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/tools/builtins.py +701 -701
  22. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova.egg-info/PKG-INFO +33 -17
  23. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova.egg-info/SOURCES.txt +1 -0
  24. {agentnova-0.2.2 → agentnova-0.2.3}/pyproject.toml +1 -1
  25. {agentnova-0.2.2 → agentnova-0.2.3}/tests/test_acp_integration.py +217 -217
  26. {agentnova-0.2.2 → agentnova-0.2.3}/tests/test_acp_subagents.py +310 -310
  27. {agentnova-0.2.2 → agentnova-0.2.3}/LICENSE +0 -0
  28. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/acp_plugin.py +0 -0
  29. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/agent_mode.py +0 -0
  30. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/bitnet_setup.py +0 -0
  31. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/config.py +0 -0
  32. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/examples/00_backend_demo.py +0 -0
  33. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/examples/01_basic_agent.py +0 -0
  34. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/examples/02_tool_agent.py +0 -0
  35. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/examples/03_orchestrator.py +0 -0
  36. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/examples/04_comprehensive_test.py +0 -0
  37. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/examples/05_tool_tests.py +0 -0
  38. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/examples/06_interactive_chat.py +0 -0
  39. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/examples/07_model_comparison.py +0 -0
  40. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/examples/08_robust_comparison.py +0 -0
  41. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/examples/09_expanded_benchmark.py +0 -0
  42. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/examples/12_batch_operations.py +0 -0
  43. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/examples/13_shutdown_demo.py +0 -0
  44. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/examples/14_gsm8k_benchmark.py +0 -0
  45. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/shared_args.py +0 -0
  46. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/acp/SKILL.md +0 -0
  47. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/datetime/SKILL.md +0 -0
  48. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/skill-creator/SKILL.md +0 -0
  49. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/__init__.py +0 -0
  50. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/aggregate_benchmark.py +0 -0
  51. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/generate_report.py +0 -0
  52. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/improve_description.py +0 -0
  53. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/init_skill.py +0 -0
  54. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/package_skill.py +0 -0
  55. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/quick_validate.py +0 -0
  56. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/run_eval.py +0 -0
  57. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/run_loop.py +0 -0
  58. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/security_scan.py +0 -0
  59. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/test_package_skill.py +0 -0
  60. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/test_quick_validate.py +0 -0
  61. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/utils.py +0 -0
  62. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/skill-creator/scripts/validate.py +0 -0
  63. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/skills/web_search/SKILL.md +0 -0
  64. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova/tools/sandboxed_repl.py +0 -0
  65. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova.egg-info/dependency_links.txt +0 -0
  66. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova.egg-info/entry_points.txt +0 -0
  67. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova.egg-info/requires.txt +0 -0
  68. {agentnova-0.2.2 → agentnova-0.2.3}/agentnova.egg-info/top_level.txt +0 -0
  69. {agentnova-0.2.2 → agentnova-0.2.3}/localclaw/__init__.py +0 -0
  70. {agentnova-0.2.2 → agentnova-0.2.3}/localclaw/__main__.py +0 -0
  71. {agentnova-0.2.2 → agentnova-0.2.3}/setup.cfg +0 -0
  72. {agentnova-0.2.2 → 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.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,7 +42,11 @@ 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
+ [![pip - agentnova](https://img.shields.io/badge/pip-agentnova-2ea44f?logo=PyPi)](https://pypi.org/project/agentnova/)
48
+ [![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)
49
+
46
50
  ---
47
51
 
48
52
  ## 📚 Documentation
@@ -195,20 +199,31 @@ agentnova models --tool_support
195
199
 
196
200
  ### Performance by Tool Support
197
201
 
198
- Recent test results with native tool synthesis:
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):**
199
213
 
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 |
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 |
206
221
 
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
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
212
227
 
213
228
  ---
214
229
 
@@ -259,7 +274,7 @@ Output shows:
259
274
  - **Tool Support** - `✓ native`, `ReAct`, `○ none`, or `untested`
260
275
 
261
276
  ```
262
- ⚛️ AgentNova R02 Models
277
+ ⚛️ AgentNova R02.3 Models
263
278
  Model Family Context Tool Support
264
279
  ──────────────────────────────────────────────────────────────────────────────
265
280
  gemma3:270m gemma3 32K ○ none
@@ -276,8 +291,9 @@ Output shows:
276
291
  # List all available tests
277
292
  agentnova test --list
278
293
 
279
- # Run a quick test suite
280
- agentnova test quick
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
281
297
 
282
298
  # Run GSM8K benchmark (50 math questions)
283
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,7 +6,11 @@ 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
+ [![pip - agentnova](https://img.shields.io/badge/pip-agentnova-2ea44f?logo=PyPi)](https://pypi.org/project/agentnova/)
12
+ [![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)
13
+
10
14
  ---
11
15
 
12
16
  ## 📚 Documentation
@@ -159,20 +163,31 @@ agentnova models --tool_support
159
163
 
160
164
  ### Performance by Tool Support
161
165
 
162
- Recent test results with native tool synthesis:
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):**
163
177
 
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 |
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 |
170
185
 
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
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
176
191
 
177
192
  ---
178
193
 
@@ -223,7 +238,7 @@ Output shows:
223
238
  - **Tool Support** - `✓ native`, `ReAct`, `○ none`, or `untested`
224
239
 
225
240
  ```
226
- ⚛️ AgentNova R02 Models
241
+ ⚛️ AgentNova R02.3 Models
227
242
  Model Family Context Tool Support
228
243
  ──────────────────────────────────────────────────────────────────────────────
229
244
  gemma3:270m gemma3 32K ○ none
@@ -240,8 +255,9 @@ Output shows:
240
255
  # List all available tests
241
256
  agentnova test --list
242
257
 
243
- # Run a quick test suite
244
- agentnova test quick
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
245
261
 
246
262
  # Run GSM8K benchmark (50 math questions)
247
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",
@@ -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
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python3
2
2
  """
3
- ⚛️ AgentNova R02 — CLI
3
+ ⚛️ AgentNova R02.3 — CLI
4
4
  Entry point: agentnova <command> [options]
5
5
 
6
6
  Commands:
@@ -924,7 +924,7 @@ def cmd_models(args):
924
924
  print(red("✗ bitnet_client.py not found. Copy it into agentnova/."))
925
925
  sys.exit(1)
926
926
 
927
- print(bold("\n⚛️ AgentNova R02 BitNet Model (Remote)"))
927
+ print(bold("\n⚛️ AgentNova R02.3 BitNet Model (Remote)"))
928
928
 
929
929
  # We use the client logic to see what is actually running at the URL
930
930
  try:
@@ -952,7 +952,7 @@ def cmd_models(args):
952
952
  print(yellow("No models found. Pull one with: ollama pull llama3.2:3b"))
953
953
  return
954
954
 
955
- print(bold("\n⚛️ AgentNova R02 Models") + dim(" · Written by VTSTech · https://www.vts-tech.org · https://github.com/VTSTech/AgentNova"))
955
+ print(bold("\n⚛️ AgentNova R02.3 Models") + dim(" · Written by VTSTech · https://www.vts-tech.org · https://github.com/VTSTech/AgentNova"))
956
956
 
957
957
  # Load tested models from storage
958
958
  tested_models = _load_tested_models()
@@ -1091,7 +1091,7 @@ def cmd_models(args):
1091
1091
 
1092
1092
  def cmd_tools(args):
1093
1093
  tools = BUILTIN_REGISTRY.all()
1094
- print(bold("\n⚛️ AgentNova R02 Tools") + dim(" · Written by VTSTech · https://www.vts-tech.org · https://github.com/VTSTech/AgentNova"))
1094
+ print(bold("\n⚛️ AgentNova R02.3 Tools") + dim(" · Written by VTSTech · https://www.vts-tech.org · https://github.com/VTSTech/AgentNova"))
1095
1095
  print(bold(f"{'Tool':<20} Description"))
1096
1096
  print(dim("─" * 70))
1097
1097
  for t in tools:
@@ -1116,7 +1116,7 @@ def cmd_modelfile(args):
1116
1116
  sys.exit(1)
1117
1117
 
1118
1118
  model = args.model
1119
- print(bold(f"\n⚛️ AgentNova R02 Modelfile") + dim(" · Written by VTSTech · https://www.vts-tech.org · https://github.com/VTSTech/AgentNova"))
1119
+ print(bold(f"\n⚛️ AgentNova R02.3 Modelfile") + dim(" · Written by VTSTech · https://www.vts-tech.org · https://github.com/VTSTech/AgentNova"))
1120
1120
  print()
1121
1121
 
1122
1122
  try:
@@ -1181,7 +1181,7 @@ def cmd_skills(args):
1181
1181
  loader = SkillLoader()
1182
1182
  skills = loader.list_skills()
1183
1183
 
1184
- print(bold("\n⚛️ AgentNova R02 Skills") + dim(" · Written by VTSTech · https://www.vts-tech.org · https://github.com/VTSTech/AgentNova"))
1184
+ print(bold("\n⚛️ AgentNova R02.3 Skills") + dim(" · Written by VTSTech · https://www.vts-tech.org · https://github.com/VTSTech/AgentNova"))
1185
1185
 
1186
1186
  if not skills:
1187
1187
  print(yellow(" No skills found."))
@@ -1266,7 +1266,7 @@ def cmd_run(args):
1266
1266
  if acp_plugin:
1267
1267
  bootstrap_result = acp_plugin.bootstrap(claim_primary=False) # AgentNova is secondary
1268
1268
 
1269
- print(bold("⚛️ AgentNova R02") + dim(" · Written by VTSTech · https://www.vts-tech.org · https://github.com/VTSTech/AgentNova"))
1269
+ print(bold("⚛️ AgentNova R02.3") + dim(" · Written by VTSTech · https://www.vts-tech.org · https://github.com/VTSTech/AgentNova"))
1270
1270
  print(f"Prompt: {args.prompt}")
1271
1271
 
1272
1272
  # Log user message to ACP
@@ -1359,7 +1359,7 @@ def cmd_chat(args):
1359
1359
  parts.append("]")
1360
1360
  status = " ".join(parts)
1361
1361
 
1362
- print(bold(f"\n⚛️ AgentNova R02 chat") + dim(f" {status} · Written by VTSTech · https://www.vts-tech.org · https://github.com/VTSTech/AgentNova"))
1362
+ print(bold(f"\n⚛️ AgentNova R02.3 chat") + dim(f" {status} · Written by VTSTech · https://www.vts-tech.org · https://github.com/VTSTech/AgentNova"))
1363
1363
  print(dim(" Type 'exit', 'quit', or Ctrl+C to quit."))
1364
1364
  print(dim(" Type '/help' to see all available commands."))
1365
1365
  print(dim(" Type '/ollama' to manage Ollama models (works with remote Ollama)."))
@@ -1909,7 +1909,7 @@ def cmd_agent(args):
1909
1909
  parts.append("]")
1910
1910
  status = " ".join(parts)
1911
1911
 
1912
- print(bold(f"\n⚛️ AgentNova R02 agent mode") + dim(f" {status} · Written by VTSTech · https://www.vts-tech.org · https://github.com/VTSTech/AgentNova"))
1912
+ print(bold(f"\n⚛️ AgentNova R02.3 agent mode") + dim(f" {status} · Written by VTSTech · https://www.vts-tech.org · https://github.com/VTSTech/AgentNova"))
1913
1913
  print(dim(" Agent mode: Give tasks and the agent will work autonomously."))
1914
1914
  print(dim(" Type '/help' to see available commands."))
1915
1915
  print(dim(" ─────────────────────────────────────"))
@@ -2290,11 +2290,12 @@ def cmd_test(args):
2290
2290
  "13_acp": "Shutdown demo with ACP tracking",
2291
2291
  "14": "GSM8K benchmark - 50 math questions",
2292
2292
  "14_acp": "GSM8K benchmark with ACP tracking",
2293
+ "15": "Quick diagnostic - 5 questions, ~30s/model",
2293
2294
  "backend": "Backend demo - Ollama/BitNet switching",
2294
2295
  }
2295
2296
 
2296
2297
  # Quick test set (skips long-running benchmarks)
2297
- QUICK_TESTS = ["01", "02", "03", "04", "05", "10", "11"]
2298
+ QUICK_TESTS = ["01", "02", "03", "04", "05", "10", "11", "15"]
2298
2299
 
2299
2300
  if args.list:
2300
2301
  print(bold("\n⚛️ AgentNova Test Examples"))
@@ -2456,7 +2457,7 @@ def build_parser() -> argparse.ArgumentParser:
2456
2457
 
2457
2458
  parser = argparse.ArgumentParser(
2458
2459
  prog="agentnova",
2459
- description="⚛️ AgentNova R02 - local agentic AI powered by Ollama",
2460
+ description="⚛️ AgentNova R02.3 - local agentic AI powered by Ollama",
2460
2461
  )
2461
2462
 
2462
2463
  sub = parser.add_subparsers(dest="command", metavar="command")