agentnova 0.3.1__tar.gz → 0.3.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 (98) hide show
  1. {agentnova-0.3.1 → agentnova-0.3.3}/PKG-INFO +55 -5
  2. {agentnova-0.3.1 → agentnova-0.3.3}/README.md +55 -5
  3. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/__init__.py +1 -1
  4. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/acp_plugin.py +149 -0
  5. agentnova-0.3.3/agentnova/agent.py +1020 -0
  6. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/backends/__init__.py +11 -3
  7. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/backends/base.py +4 -4
  8. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/backends/bitnet.py +1 -1
  9. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/backends/ollama.py +358 -2
  10. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/cli.py +274 -98
  11. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/config.py +17 -6
  12. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/core/__init__.py +59 -7
  13. agentnova-0.3.3/agentnova/core/error_recovery.py +725 -0
  14. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/core/helpers.py +89 -12
  15. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/core/memory.py +30 -10
  16. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/core/model_config.py +2 -2
  17. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/core/models.py +12 -2
  18. agentnova-0.3.3/agentnova/core/openresponses.py +812 -0
  19. agentnova-0.3.3/agentnova/core/prompts.py +324 -0
  20. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/core/tool_parse.py +127 -212
  21. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/core/types.py +15 -1
  22. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/examples/00_basic_agent.py +22 -6
  23. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/examples/01_quick_diagnostic.py +40 -11
  24. agentnova-0.3.3/agentnova/examples/02_tool_test.py +942 -0
  25. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/examples/03_reasoning_test.py +3 -0
  26. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/examples/04_gsm8k_benchmark.py +5 -2
  27. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/examples/05_common_sense.py +3 -0
  28. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/examples/06_causal_reasoning.py +3 -0
  29. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/examples/07_logical_deduction.py +3 -0
  30. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/examples/08_reading_comprehension.py +3 -0
  31. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/examples/09_general_knowledge.py +3 -0
  32. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/examples/10_implicit_reasoning.py +3 -0
  33. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/examples/11_analogical_reasoning.py +3 -0
  34. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/model_discovery.py +140 -0
  35. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/__init__.py +16 -2
  36. agentnova-0.3.3/agentnova/skills/loader.py +1893 -0
  37. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/soul/__init__.py +3 -1
  38. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/soul/loader.py +514 -5
  39. agentnova-0.3.3/agentnova/souls/nova-helper/IDENTITY.md +14 -0
  40. agentnova-0.3.3/agentnova/souls/nova-helper/SOUL.md +127 -0
  41. agentnova-0.3.3/agentnova/souls/nova-helper/STYLE.md +83 -0
  42. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/souls/nova-helper/soul.json +30 -30
  43. agentnova-0.3.3/agentnova/tools/builtins.py +650 -0
  44. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova.egg-info/PKG-INFO +55 -5
  45. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova.egg-info/SOURCES.txt +2 -1
  46. {agentnova-0.3.1 → agentnova-0.3.3}/pyproject.toml +1 -1
  47. agentnova-0.3.1/agentnova/agent.py +0 -981
  48. agentnova-0.3.1/agentnova/core/prompts.py +0 -401
  49. agentnova-0.3.1/agentnova/examples/02_tool_test.py +0 -283
  50. agentnova-0.3.1/agentnova/skills/loader.py +0 -445
  51. agentnova-0.3.1/agentnova/soul/___init___.py +0 -97
  52. agentnova-0.3.1/agentnova/souls/nova-helper/IDENTITY.md +0 -33
  53. agentnova-0.3.1/agentnova/souls/nova-helper/SOUL.md +0 -62
  54. agentnova-0.3.1/agentnova/souls/nova-helper/STYLE.md +0 -75
  55. agentnova-0.3.1/agentnova/tools/builtins.py +0 -412
  56. {agentnova-0.3.1 → agentnova-0.3.3}/LICENSE +0 -0
  57. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/__main__.py +0 -0
  58. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/agent_mode.py +0 -0
  59. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/core/args_normal.py +0 -0
  60. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/core/math_prompts.py +0 -0
  61. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/core/model_family_config.py +0 -0
  62. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/examples/__init__.py +0 -0
  63. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/orchestrator.py +0 -0
  64. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/orchestrator_enhanced.py +0 -0
  65. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/py.typed +0 -0
  66. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/shared_args.py +0 -0
  67. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/acp/SKILL.md +0 -0
  68. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/datetime/SKILL.md +0 -0
  69. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/skill-creator/SKILL.md +0 -0
  70. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/skill-creator/scripts/__init__.py +0 -0
  71. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/skill-creator/scripts/aggregate_benchmark.py +0 -0
  72. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/skill-creator/scripts/generate_report.py +0 -0
  73. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/skill-creator/scripts/improve_description.py +0 -0
  74. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/skill-creator/scripts/init_skill.py +0 -0
  75. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/skill-creator/scripts/package_skill.py +0 -0
  76. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/skill-creator/scripts/quick_validate.py +0 -0
  77. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/skill-creator/scripts/run_eval.py +0 -0
  78. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/skill-creator/scripts/run_loop.py +0 -0
  79. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/skill-creator/scripts/security_scan.py +0 -0
  80. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/skill-creator/scripts/test_package_skill.py +0 -0
  81. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/skill-creator/scripts/test_quick_validate.py +0 -0
  82. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/skill-creator/scripts/utils.py +0 -0
  83. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/skill-creator/scripts/validate.py +0 -0
  84. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/skills/web-search/SKILL.md +0 -0
  85. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/soul/types.py +0 -0
  86. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/tools/__init__.py +0 -0
  87. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/tools/registry.py +0 -0
  88. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova/tools/sandboxed_repl.py +0 -0
  89. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova.egg-info/dependency_links.txt +0 -0
  90. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova.egg-info/entry_points.txt +0 -0
  91. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova.egg-info/requires.txt +0 -0
  92. {agentnova-0.3.1 → agentnova-0.3.3}/agentnova.egg-info/top_level.txt +0 -0
  93. {agentnova-0.3.1 → agentnova-0.3.3}/localclaw/__init__.py +0 -0
  94. {agentnova-0.3.1 → agentnova-0.3.3}/localclaw-redirect/localclaw/__init__.py +0 -0
  95. {agentnova-0.3.1 → agentnova-0.3.3}/setup.cfg +0 -0
  96. {agentnova-0.3.1 → agentnova-0.3.3}/tests/test_acp_integration.py +0 -0
  97. {agentnova-0.3.1 → agentnova-0.3.3}/tests/test_acp_subagents.py +0 -0
  98. {agentnova-0.3.1 → agentnova-0.3.3}/tests/test_agent.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentnova
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: ⚛️ AgentNova - A minimal, hackable agentic framework for local LLM inference
5
5
  Author-email: VTSTech <veritas@vts-tech.org>
6
6
  Maintainer-email: VTSTech <veritas@vts-tech.org>
@@ -32,7 +32,7 @@ Requires-Dist: black>=23.0; extra == "dev"
32
32
  Requires-Dist: ruff>=0.1.0; extra == "dev"
33
33
  Dynamic: license-file
34
34
 
35
- # ⚛️ AgentNova R03.1
35
+ # ⚛️ AgentNova R03.3
36
36
 
37
37
  **Status: Alpha**
38
38
 
@@ -49,9 +49,7 @@ Inspired by the architecture of OpenClaw, rebuilt from scratch for local-first o
49
49
 
50
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
51
 
52
- <img width="801" height="603" alt="image" src="https://github.com/user-attachments/assets/457acc38-231f-4d75-aec6-fa4897fbbb88" />
53
-
54
- ---
52
+ <img width="1102" height="960" alt="image" src="https://github.com/user-attachments/assets/2a5fe9b4-93df-46a0-9383-9e01e0c0105d" />
55
53
 
56
54
  ## 📚 Documentation
57
55
 
@@ -65,10 +63,14 @@ Inspired by the architecture of OpenClaw, rebuilt from scratch for local-first o
65
63
 
66
64
  - **Zero dependencies** — Uses Python stdlib only (urllib for HTTP)
67
65
  - **Ollama + BitNet backends** — Switch with `--backend` flag
66
+ - **Dual API support** — OpenResponses (`--api resp`) and Chat-Completions (`--api comp`)
68
67
  - **Three-tier tool support** — Native, ReAct, or none (auto-detected)
69
68
  - **Small model optimized** — Fuzzy matching, argument normalization
70
69
  - **Built-in security** — Path validation, command blocklist, SSRF protection
71
70
  - **Multi-agent orchestration** — Router, pipeline, and parallel modes
71
+ - **Soul Spec v0.5** — Persona packages with progressive disclosure
72
+ - **ACP v1.0.5 integration** — Agent Control Panel for monitoring and control
73
+ - **AgentSkills spec** — Skill loading with SPDX license validation
72
74
 
73
75
  ## Installation
74
76
 
@@ -96,6 +98,9 @@ agentnova chat -m qwen2.5:0.5b --tools calculator,shell
96
98
  # Autonomous agent mode
97
99
  agentnova agent -m qwen2.5:7b --tools calculator,shell,write_file
98
100
 
101
+ # Use Chat-Completions API (OpenAI-compatible)
102
+ agentnova chat -m qwen2.5:0.5b --api comp
103
+
99
104
  # List available models
100
105
  agentnova models
101
106
 
@@ -125,6 +130,37 @@ print(result.final_answer)
125
130
  print(f"Completed in {result.total_ms:.0f}ms")
126
131
  ```
127
132
 
133
+ ### Chat-Completions Streaming
134
+
135
+ ```python
136
+ from agentnova.backends import get_backend
137
+ from agentnova.core.types import ApiMode
138
+
139
+ # Use Chat-Completions mode with streaming
140
+ backend = get_backend("ollama", api_mode=ApiMode.COMPLETIONS)
141
+
142
+ for chunk in backend.generate_completions_stream(
143
+ model="qwen2.5:0.5b",
144
+ messages=[{"role": "user", "content": "Hello!"}],
145
+ response_format={"type": "json_object"}
146
+ ):
147
+ print(chunk["delta"], end="", flush=True)
148
+ ```
149
+
150
+ ### Skill License Validation
151
+
152
+ ```python
153
+ from agentnova.skills import validate_spdx_license, parse_compatibility
154
+
155
+ # Validate SPDX license identifier
156
+ valid, msg = validate_spdx_license("MIT") # (True, "Valid SPDX identifier: MIT")
157
+ valid, msg = validate_spdx_license("Custom") # (False, "Unknown license...")
158
+
159
+ # Parse compatibility requirements
160
+ compat = parse_compatibility("python>=3.8, ollama")
161
+ # Returns: {"python": ">=3.8", "runtimes": ["ollama"], "frameworks": []}
162
+ ```
163
+
128
164
  ### Multi-Agent Orchestration
129
165
 
130
166
  ```python
@@ -220,6 +256,20 @@ agentnova config
220
256
  agentnova config --urls # Show only URLs
221
257
  ```
222
258
 
259
+ ### CLI Options (run, chat, agent)
260
+
261
+ | Option | Description |
262
+ |--------|-------------|
263
+ | `--api resp\|comp` | API mode: OpenResponses (default) or Chat-Completions |
264
+ | `--response-format text\|json` | Response format (Chat-Completions mode) |
265
+ | `--truncation auto\|disabled` | Truncation behavior for long responses |
266
+ | `--soul <path>` | Load Soul Spec persona package |
267
+ | `--soul-level 1-3` | Progressive disclosure level |
268
+ | `--num-ctx <tokens>` | Context window size (default: 4096) |
269
+ | `--timeout <seconds>` | Request timeout (default: 120) |
270
+ | `--acp` | Enable ACP (Agent Control Panel) logging |
271
+ | `--acp-url <url>` | ACP server URL |
272
+
223
273
  ## LocalClaw Redirect
224
274
 
225
275
  The `localclaw` command is provided for backward compatibility:
@@ -1,4 +1,4 @@
1
- # ⚛️ AgentNova R03.1
1
+ # ⚛️ AgentNova R03.3
2
2
 
3
3
  **Status: Alpha**
4
4
 
@@ -15,9 +15,7 @@ Inspired by the architecture of OpenClaw, rebuilt from scratch for local-first o
15
15
 
16
16
  [![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)
17
17
 
18
- <img width="801" height="603" alt="image" src="https://github.com/user-attachments/assets/457acc38-231f-4d75-aec6-fa4897fbbb88" />
19
-
20
- ---
18
+ <img width="1102" height="960" alt="image" src="https://github.com/user-attachments/assets/2a5fe9b4-93df-46a0-9383-9e01e0c0105d" />
21
19
 
22
20
  ## 📚 Documentation
23
21
 
@@ -31,10 +29,14 @@ Inspired by the architecture of OpenClaw, rebuilt from scratch for local-first o
31
29
 
32
30
  - **Zero dependencies** — Uses Python stdlib only (urllib for HTTP)
33
31
  - **Ollama + BitNet backends** — Switch with `--backend` flag
32
+ - **Dual API support** — OpenResponses (`--api resp`) and Chat-Completions (`--api comp`)
34
33
  - **Three-tier tool support** — Native, ReAct, or none (auto-detected)
35
34
  - **Small model optimized** — Fuzzy matching, argument normalization
36
35
  - **Built-in security** — Path validation, command blocklist, SSRF protection
37
36
  - **Multi-agent orchestration** — Router, pipeline, and parallel modes
37
+ - **Soul Spec v0.5** — Persona packages with progressive disclosure
38
+ - **ACP v1.0.5 integration** — Agent Control Panel for monitoring and control
39
+ - **AgentSkills spec** — Skill loading with SPDX license validation
38
40
 
39
41
  ## Installation
40
42
 
@@ -62,6 +64,9 @@ agentnova chat -m qwen2.5:0.5b --tools calculator,shell
62
64
  # Autonomous agent mode
63
65
  agentnova agent -m qwen2.5:7b --tools calculator,shell,write_file
64
66
 
67
+ # Use Chat-Completions API (OpenAI-compatible)
68
+ agentnova chat -m qwen2.5:0.5b --api comp
69
+
65
70
  # List available models
66
71
  agentnova models
67
72
 
@@ -91,6 +96,37 @@ print(result.final_answer)
91
96
  print(f"Completed in {result.total_ms:.0f}ms")
92
97
  ```
93
98
 
99
+ ### Chat-Completions Streaming
100
+
101
+ ```python
102
+ from agentnova.backends import get_backend
103
+ from agentnova.core.types import ApiMode
104
+
105
+ # Use Chat-Completions mode with streaming
106
+ backend = get_backend("ollama", api_mode=ApiMode.COMPLETIONS)
107
+
108
+ for chunk in backend.generate_completions_stream(
109
+ model="qwen2.5:0.5b",
110
+ messages=[{"role": "user", "content": "Hello!"}],
111
+ response_format={"type": "json_object"}
112
+ ):
113
+ print(chunk["delta"], end="", flush=True)
114
+ ```
115
+
116
+ ### Skill License Validation
117
+
118
+ ```python
119
+ from agentnova.skills import validate_spdx_license, parse_compatibility
120
+
121
+ # Validate SPDX license identifier
122
+ valid, msg = validate_spdx_license("MIT") # (True, "Valid SPDX identifier: MIT")
123
+ valid, msg = validate_spdx_license("Custom") # (False, "Unknown license...")
124
+
125
+ # Parse compatibility requirements
126
+ compat = parse_compatibility("python>=3.8, ollama")
127
+ # Returns: {"python": ">=3.8", "runtimes": ["ollama"], "frameworks": []}
128
+ ```
129
+
94
130
  ### Multi-Agent Orchestration
95
131
 
96
132
  ```python
@@ -186,6 +222,20 @@ agentnova config
186
222
  agentnova config --urls # Show only URLs
187
223
  ```
188
224
 
225
+ ### CLI Options (run, chat, agent)
226
+
227
+ | Option | Description |
228
+ |--------|-------------|
229
+ | `--api resp\|comp` | API mode: OpenResponses (default) or Chat-Completions |
230
+ | `--response-format text\|json` | Response format (Chat-Completions mode) |
231
+ | `--truncation auto\|disabled` | Truncation behavior for long responses |
232
+ | `--soul <path>` | Load Soul Spec persona package |
233
+ | `--soul-level 1-3` | Progressive disclosure level |
234
+ | `--num-ctx <tokens>` | Context window size (default: 4096) |
235
+ | `--timeout <seconds>` | Request timeout (default: 120) |
236
+ | `--acp` | Enable ACP (Agent Control Panel) logging |
237
+ | `--acp-url <url>` | ACP server URL |
238
+
189
239
  ## LocalClaw Redirect
190
240
 
191
241
  The `localclaw` command is provided for backward compatibility:
@@ -268,4 +318,4 @@ Contributions welcome! Please read the contributing guidelines first.
268
318
 
269
319
  - Built for local inference with [Ollama](https://ollama.ai)
270
320
  - Optimized for small, efficient models
271
- - Inspired by ReAct and other agentic frameworks
321
+ - Inspired by ReAct and other agentic frameworks
@@ -28,7 +28,7 @@ Example Usage:
28
28
  agent = Agent(model="qwen2.5:0.5b", soul="/path/to/soul/package")
29
29
  """
30
30
 
31
- __version__ = "0.3.1"
31
+ __version__ = "0.3.3"
32
32
  __author__ = "VTSTech"
33
33
  __status__ = "Alpha"
34
34
 
@@ -2059,3 +2059,152 @@ class ACPPlugin:
2059
2059
 
2060
2060
  self._log(f"A2A: Broadcast {action} to {len(results)} agent(s)")
2061
2061
  return results
2062
+
2063
+ # ------------------------------------------------------------------ #
2064
+ # Batch Context Manager (v1.0.6) #
2065
+ # ------------------------------------------------------------------ #
2066
+
2067
+ def batch_context(
2068
+ self,
2069
+ description: str = "Batch operation",
2070
+ auto_complete: bool = True,
2071
+ ):
2072
+ """
2073
+ Context manager for batch operations.
2074
+
2075
+ This provides a convenient way to group multiple activities
2076
+ into a single batch with automatic completion.
2077
+
2078
+ Parameters
2079
+ ----------
2080
+ description : str
2081
+ Description for the batch operation
2082
+ auto_complete : bool
2083
+ Whether to automatically complete all activities on exit (default: True)
2084
+
2085
+ Yields
2086
+ ------
2087
+ BatchHelper
2088
+ A helper object for adding activities to the batch
2089
+
2090
+ Example
2091
+ -------
2092
+ >>> with acp.batch_context("Read multiple config files") as batch:
2093
+ ... batch.add_read("/etc/config1.yaml")
2094
+ ... batch.add_read("/etc/config2.yaml")
2095
+ ... batch.add_read("/etc/config3.yaml")
2096
+ >>> # All activities are automatically started and completed
2097
+ """
2098
+ return _BatchContext(self, description, auto_complete)
2099
+
2100
+
2101
+ class _BatchContext:
2102
+ """
2103
+ Internal batch context manager for grouping activities.
2104
+
2105
+ Collects activities and submits them as a batch when the context exits.
2106
+ """
2107
+
2108
+ def __init__(self, acp: "ACPPlugin", description: str, auto_complete: bool):
2109
+ self._acp = acp
2110
+ self._description = description
2111
+ self._auto_complete = auto_complete
2112
+ self._activities: list[dict] = []
2113
+ self._results: list[dict] = []
2114
+ self._activity_ids: list[str] = []
2115
+
2116
+ def add(self, action: str, target: str, details: str = "", **kwargs) -> None:
2117
+ """
2118
+ Add an activity to the batch.
2119
+
2120
+ Parameters
2121
+ ----------
2122
+ action : str
2123
+ Action type (READ, WRITE, EDIT, BASH, etc.)
2124
+ target : str
2125
+ Target for the action (file path, command, etc.)
2126
+ details : str
2127
+ Optional details about the activity
2128
+ **kwargs
2129
+ Additional fields (content_size, priority, etc.)
2130
+ """
2131
+ self._activities.append({
2132
+ "action": action,
2133
+ "target": target,
2134
+ "details": details,
2135
+ **kwargs
2136
+ })
2137
+
2138
+ def add_read(self, path: str, content_size: int = 0) -> None:
2139
+ """Add a READ activity for a file."""
2140
+ self.add("READ", path, f"Read file: {path}", content_size=content_size)
2141
+
2142
+ def add_write(self, path: str, content_size: int = 0) -> None:
2143
+ """Add a WRITE activity for a file."""
2144
+ self.add("WRITE", path, f"Write file: {path}", content_size=content_size)
2145
+
2146
+ def add_edit(self, path: str, content_size: int = 0) -> None:
2147
+ """Add an EDIT activity for a file."""
2148
+ self.add("EDIT", path, f"Edit file: {path}", content_size=content_size)
2149
+
2150
+ def add_bash(self, command: str) -> None:
2151
+ """Add a BASH activity for a command."""
2152
+ self.add("BASH", command[:100], f"Execute: {command[:200]}")
2153
+
2154
+ def add_search(self, query: str) -> None:
2155
+ """Add a SEARCH activity for a web search."""
2156
+ self.add("SEARCH", query[:100], f"Search: {query[:200]}")
2157
+
2158
+ def add_api(self, url: str, method: str = "GET") -> None:
2159
+ """Add an API activity for an HTTP request."""
2160
+ self.add("API", url[:100], f"{method} {url[:200]}")
2161
+
2162
+ @property
2163
+ def activity_ids(self) -> list[str]:
2164
+ """Get the list of activity IDs (available after entering context)."""
2165
+ return self._activity_ids
2166
+
2167
+ @property
2168
+ def results(self) -> list[dict]:
2169
+ """Get the batch results (available after exiting context)."""
2170
+ return self._results
2171
+
2172
+ def __enter__(self):
2173
+ """Start all activities in the batch."""
2174
+ if not self._acp.enabled or not self._activities:
2175
+ return self
2176
+
2177
+ # Start all activities in batch
2178
+ result = self._acp.batch_start(self._activities)
2179
+ self._results = result.get("results", [])
2180
+ self._activity_ids = [
2181
+ r.get("activity_id") for r in self._results if r.get("activity_id")
2182
+ ]
2183
+
2184
+ # Track activities
2185
+ for aid in self._activity_ids:
2186
+ if aid:
2187
+ self._acp._activity_stack.append(aid)
2188
+
2189
+ self._acp._log(f"Batch started: {len(self._activity_ids)} activities for '{self._description}'")
2190
+ return self
2191
+
2192
+ def __exit__(self, exc_type, exc_val, exc_tb):
2193
+ """Complete all activities in the batch."""
2194
+ if not self._acp.enabled or not self._activity_ids:
2195
+ return False
2196
+
2197
+ if self._auto_complete:
2198
+ # Complete all activities
2199
+ completions = []
2200
+ for aid in self._activity_ids:
2201
+ result = "Completed" if exc_type is None else f"Error: {exc_val}"
2202
+ completions.append({
2203
+ "activity_id": aid,
2204
+ "result": result,
2205
+ })
2206
+
2207
+ self._acp.batch_complete(completions)
2208
+ self._acp._log(f"Batch completed: {len(self._activity_ids)} activities")
2209
+
2210
+ return False # Don't suppress exceptions