bone-agent 1.4.0 → 2.0.0
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.
- package/bin/bone.js +39 -0
- package/package.json +25 -39
- package/LICENSE +0 -21
- package/README.md +0 -201
- package/bin/npm-wrapper.js +0 -235
- package/bin/rg +0 -0
- package/bin/rg.exe +0 -0
- package/config.yaml.example +0 -144
- package/prompts/main/ask_questions.md +0 -31
- package/prompts/main/batch_independent_calls.md +0 -5
- package/prompts/main/casual_interactions.md +0 -11
- package/prompts/main/code_references.md +0 -8
- package/prompts/main/communication_style.md +0 -12
- package/prompts/main/context_reliability.md +0 -12
- package/prompts/main/conversational_tool_calling.md +0 -15
- package/prompts/main/dream.md +0 -50
- package/prompts/main/editing_pattern.md +0 -13
- package/prompts/main/error_handling.md +0 -6
- package/prompts/main/exploration_pattern.md +0 -21
- package/prompts/main/intro.md +0 -1
- package/prompts/main/obsidian.md +0 -16
- package/prompts/main/obsidian_project.md +0 -79
- package/prompts/main/professional_objectivity.md +0 -3
- package/prompts/main/skills.md +0 -3
- package/prompts/main/targeted_searching.md +0 -10
- package/prompts/main/task_lists_pattern.md +0 -8
- package/prompts/main/temp_folder.md +0 -9
- package/prompts/main/think_before_acting.md +0 -10
- package/prompts/main/tone_and_style.md +0 -4
- package/prompts/main/tool_preferences.md +0 -24
- package/prompts/main/trust_subagent_context.md +0 -21
- package/prompts/main/when_to_use_sub_agent.md +0 -7
- package/prompts/micro/ask_questions.md +0 -1
- package/prompts/micro/batch_independent_calls.md +0 -1
- package/prompts/micro/casual_interactions.md +0 -1
- package/prompts/micro/code_references.md +0 -1
- package/prompts/micro/communication_style.md +0 -1
- package/prompts/micro/context_reliability.md +0 -1
- package/prompts/micro/conversational_tool_calling.md +0 -1
- package/prompts/micro/editing_pattern.md +0 -1
- package/prompts/micro/error_handling.md +0 -1
- package/prompts/micro/exploration_pattern.md +0 -1
- package/prompts/micro/intro.md +0 -1
- package/prompts/micro/obsidian.md +0 -4
- package/prompts/micro/obsidian_project.md +0 -5
- package/prompts/micro/professional_objectivity.md +0 -1
- package/prompts/micro/skills.md +0 -1
- package/prompts/micro/targeted_searching.md +0 -1
- package/prompts/micro/task_lists_pattern.md +0 -1
- package/prompts/micro/temp_folder.md +0 -1
- package/prompts/micro/think_before_acting.md +0 -5
- package/prompts/micro/tone_and_style.md +0 -1
- package/prompts/micro/tool_preferences.md +0 -1
- package/prompts/micro/trust_subagent_context.md +0 -1
- package/prompts/micro/when_to_use_sub_agent.md +0 -1
- package/requirements.txt +0 -9
- package/src/__init__.py +0 -11
- package/src/core/__init__.py +0 -1
- package/src/core/agentic.py +0 -1085
- package/src/core/chat_manager.py +0 -1577
- package/src/core/config_manager.py +0 -260
- package/src/core/cron.py +0 -578
- package/src/core/cron_allowlist.py +0 -118
- package/src/core/memory.py +0 -145
- package/src/core/metadata.py +0 -75
- package/src/core/retry.py +0 -71
- package/src/core/skills.py +0 -463
- package/src/core/sub_agent.py +0 -376
- package/src/core/tool_approval.py +0 -220
- package/src/core/tool_feedback.py +0 -789
- package/src/exceptions.py +0 -79
- package/src/llm/__init__.py +0 -1
- package/src/llm/client.py +0 -176
- package/src/llm/codex_provider.py +0 -350
- package/src/llm/config.py +0 -536
- package/src/llm/prompts.py +0 -494
- package/src/llm/providers.py +0 -438
- package/src/llm/streaming.py +0 -163
- package/src/llm/token_tracker.py +0 -399
- package/src/tools/__init__.py +0 -151
- package/src/tools/constants.py +0 -59
- package/src/tools/create_file.py +0 -136
- package/src/tools/directory.py +0 -389
- package/src/tools/edit.py +0 -549
- package/src/tools/file_reader.py +0 -322
- package/src/tools/helpers/__init__.py +0 -99
- package/src/tools/helpers/base.py +0 -599
- package/src/tools/helpers/converters.py +0 -44
- package/src/tools/helpers/file_helpers.py +0 -189
- package/src/tools/helpers/formatters.py +0 -411
- package/src/tools/helpers/loader.py +0 -145
- package/src/tools/helpers/parallel_executor.py +0 -231
- package/src/tools/helpers/path_resolver.py +0 -283
- package/src/tools/helpers/plugin_manifest.py +0 -185
- package/src/tools/obsidian.py +0 -96
- package/src/tools/review_sub_agent.py +0 -190
- package/src/tools/rg_search.py +0 -477
- package/src/tools/search_plugins.py +0 -177
- package/src/tools/select_option.py +0 -600
- package/src/tools/shell.py +0 -302
- package/src/tools/sub_agent.py +0 -139
- package/src/tools/task_list.py +0 -269
- package/src/tools/web_search.py +0 -61
- package/src/ui/__init__.py +0 -1
- package/src/ui/banner.py +0 -87
- package/src/ui/commands.py +0 -3131
- package/src/ui/displays.py +0 -239
- package/src/ui/loader.py +0 -284
- package/src/ui/main.py +0 -643
- package/src/ui/prompt_utils.py +0 -113
- package/src/ui/setting_selector.py +0 -590
- package/src/ui/setup_wizard.py +0 -294
- package/src/ui/sub_agent_panel.py +0 -234
- package/src/ui/tool_confirmation.py +0 -226
- package/src/utils/__init__.py +0 -1
- package/src/utils/citation_parser.py +0 -199
- package/src/utils/editor.py +0 -207
- package/src/utils/gitignore_filter.py +0 -149
- package/src/utils/logger.py +0 -254
- package/src/utils/paths.py +0 -30
- package/src/utils/result_parsers.py +0 -108
- package/src/utils/safe_commands.py +0 -243
- package/src/utils/settings.py +0 -195
- package/src/utils/user_message_logger.py +0 -120
- package/src/utils/validation.py +0 -201
- package/src/utils/web_search.py +0 -173
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
import shutil
|
|
5
|
-
from typing import Dict, Any, Optional
|
|
6
|
-
import logging
|
|
7
|
-
import yaml
|
|
8
|
-
from llm import config as llm_config
|
|
9
|
-
|
|
10
|
-
logger = logging.getLogger(__name__)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class ConfigManager:
|
|
14
|
-
|
|
15
|
-
def __init__(self, config_path: Optional[Path] = None):
|
|
16
|
-
self.config_path = config_path or llm_config.CONFIG_PATH
|
|
17
|
-
self._cached_data = None
|
|
18
|
-
|
|
19
|
-
def load(self, force_reload: bool = False) -> Dict[str, Any]:
|
|
20
|
-
"""Load configuration from file, using cache if available.
|
|
21
|
-
|
|
22
|
-
Args:
|
|
23
|
-
force_reload: If True, bypass cache and reload from disk
|
|
24
|
-
|
|
25
|
-
Returns:
|
|
26
|
-
Configuration dictionary
|
|
27
|
-
"""
|
|
28
|
-
if not force_reload and self._cached_data is not None:
|
|
29
|
-
return self._cached_data
|
|
30
|
-
|
|
31
|
-
if not self.config_path.exists():
|
|
32
|
-
self._cached_data = llm_config.generate_config_template()
|
|
33
|
-
return self._cached_data
|
|
34
|
-
|
|
35
|
-
try:
|
|
36
|
-
with open(self.config_path, 'r', encoding='utf-8-sig') as f:
|
|
37
|
-
self._cached_data = yaml.safe_load(f) or {}
|
|
38
|
-
|
|
39
|
-
# Migrate legacy provider IDs to current names.
|
|
40
|
-
old_provider = self._cached_data.get('LAST_PROVIDER')
|
|
41
|
-
if old_provider in ('vmcode_proxy', 'vmcode_free', 'vmcode'):
|
|
42
|
-
logger.info("Migrating provider name '%s' -> 'bone'", old_provider)
|
|
43
|
-
self._cached_data['LAST_PROVIDER'] = 'bone'
|
|
44
|
-
self.save(self._cached_data, create_backup=True)
|
|
45
|
-
elif old_provider == 'codex_plan':
|
|
46
|
-
logger.info("Migrating provider name '%s' -> 'codex'", old_provider)
|
|
47
|
-
self._cached_data['LAST_PROVIDER'] = 'codex'
|
|
48
|
-
self.save(self._cached_data, create_backup=True)
|
|
49
|
-
|
|
50
|
-
return self._cached_data
|
|
51
|
-
except yaml.YAMLError as e:
|
|
52
|
-
logger.error(f"Failed to parse config file {self.config_path}: {e}")
|
|
53
|
-
logger.warning("Using default configuration template")
|
|
54
|
-
self._cached_data = llm_config.generate_config_template()
|
|
55
|
-
return self._cached_data
|
|
56
|
-
|
|
57
|
-
def save(self, config_data: Dict[str, Any], create_backup: bool = False):
|
|
58
|
-
if create_backup and self.config_path.exists():
|
|
59
|
-
backup_path = self.config_path.with_suffix('.backup')
|
|
60
|
-
shutil.copy2(self.config_path, backup_path)
|
|
61
|
-
|
|
62
|
-
with open(self.config_path, 'w', encoding='utf-8-sig') as f:
|
|
63
|
-
yaml.dump(config_data, f, default_flow_style=False, sort_keys=False, allow_unicode=True)
|
|
64
|
-
|
|
65
|
-
self._cached_data = config_data
|
|
66
|
-
# Note: Config is read from disk on reload. Call reload_config() after changes.
|
|
67
|
-
|
|
68
|
-
def update_field(self, key: str, value: Any, create_backup: bool = False) -> Optional[Path]:
|
|
69
|
-
"""Update a single configuration field.
|
|
70
|
-
|
|
71
|
-
Args:
|
|
72
|
-
key: Configuration key to update
|
|
73
|
-
value: New value for the key
|
|
74
|
-
create_backup: If True, create a backup before saving
|
|
75
|
-
|
|
76
|
-
Returns:
|
|
77
|
-
Backup path if backup was created, None otherwise
|
|
78
|
-
"""
|
|
79
|
-
config_data = self.load(force_reload=True)
|
|
80
|
-
config_data[key] = value
|
|
81
|
-
|
|
82
|
-
backup_path = None
|
|
83
|
-
if create_backup and self.config_path.exists():
|
|
84
|
-
backup_path = self.config_path.with_suffix('.backup')
|
|
85
|
-
|
|
86
|
-
self.save(config_data, create_backup=create_backup)
|
|
87
|
-
return backup_path
|
|
88
|
-
|
|
89
|
-
def set_provider(self, provider_name: str) -> Optional[Path]:
|
|
90
|
-
return self.update_field('LAST_PROVIDER', provider_name)
|
|
91
|
-
|
|
92
|
-
def _extract_model_pricing(self, model_name: str, config: Dict[str, Any] | None = None) -> Dict[str, float]:
|
|
93
|
-
"""Extract pricing for a model from MODEL_PRICES.
|
|
94
|
-
|
|
95
|
-
Delegates to llm_config.get_model_cost() — single source of truth.
|
|
96
|
-
"""
|
|
97
|
-
cost_in, cost_out = llm_config.get_model_cost(model_name, config=config)
|
|
98
|
-
return {'in': cost_in, 'out': cost_out}
|
|
99
|
-
|
|
100
|
-
def get_usage_costs(self, provider: str = None, model: str = None) -> Dict[str, float]:
|
|
101
|
-
"""Get usage costs for a specific model.
|
|
102
|
-
|
|
103
|
-
Args:
|
|
104
|
-
provider: Provider name (e.g., 'openrouter', 'glm', 'openai').
|
|
105
|
-
If None, uses the last provider from config.
|
|
106
|
-
model: Model name (e.g., 'minimax/minimax-m2.5', 'GLM-4.7').
|
|
107
|
-
If None, uses the current model from the provider.
|
|
108
|
-
|
|
109
|
-
Returns:
|
|
110
|
-
Dict with 'in' and 'out' cost values per 1M tokens
|
|
111
|
-
"""
|
|
112
|
-
config_data = self.load()
|
|
113
|
-
|
|
114
|
-
if provider is None:
|
|
115
|
-
provider = config_data.get('LAST_PROVIDER', 'glm')
|
|
116
|
-
|
|
117
|
-
# Get model name from config if not provided
|
|
118
|
-
if model is None:
|
|
119
|
-
provider_model_map = {
|
|
120
|
-
'bone': 'BONE_PROXY_MODEL',
|
|
121
|
-
'codex': 'CODEX_PLAN_MODEL',
|
|
122
|
-
'openrouter': 'OPENROUTER_MODEL',
|
|
123
|
-
'glm': 'GLM_MODEL',
|
|
124
|
-
'glm_plan': 'GLM_PLAN_MODEL',
|
|
125
|
-
'openai': 'OPENAI_MODEL',
|
|
126
|
-
'gemini': 'GEMINI_MODEL',
|
|
127
|
-
'minimax': 'MINIMAX_MODEL',
|
|
128
|
-
'minimax_plan': 'MINIMAX_PLAN_MODEL',
|
|
129
|
-
'anthropic': 'ANTHROPIC_MODEL',
|
|
130
|
-
'kimi': 'KIMI_MODEL'
|
|
131
|
-
}
|
|
132
|
-
model_key = provider_model_map.get(provider.lower())
|
|
133
|
-
if model_key:
|
|
134
|
-
model = config_data.get(model_key, '')
|
|
135
|
-
|
|
136
|
-
return self._extract_model_pricing(model, config=config_data)
|
|
137
|
-
|
|
138
|
-
def set_model(self, provider_name: str, model: str) -> Optional[Path]:
|
|
139
|
-
"""Set model for a specific provider.
|
|
140
|
-
|
|
141
|
-
Args:
|
|
142
|
-
provider_name: Provider name (e.g., 'openrouter', 'glm', 'local', 'openai')
|
|
143
|
-
model: Model name/path to set
|
|
144
|
-
|
|
145
|
-
Returns:
|
|
146
|
-
Backup path if backup was created, None otherwise
|
|
147
|
-
"""
|
|
148
|
-
# Map provider names to their config keys
|
|
149
|
-
provider_keys = {
|
|
150
|
-
'local': 'LOCAL_MODEL_PATH',
|
|
151
|
-
'bone': 'BONE_PROXY_MODEL',
|
|
152
|
-
'codex': 'CODEX_PLAN_MODEL',
|
|
153
|
-
'openrouter': 'OPENROUTER_MODEL',
|
|
154
|
-
'glm': 'GLM_MODEL',
|
|
155
|
-
'glm_plan': 'GLM_PLAN_MODEL',
|
|
156
|
-
'openai': 'OPENAI_MODEL',
|
|
157
|
-
'gemini': 'GEMINI_MODEL',
|
|
158
|
-
'minimax': 'MINIMAX_MODEL',
|
|
159
|
-
'minimax_plan': 'MINIMAX_PLAN_MODEL',
|
|
160
|
-
'anthropic': 'ANTHROPIC_MODEL',
|
|
161
|
-
'kimi': 'KIMI_MODEL'
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if provider_name not in provider_keys:
|
|
165
|
-
raise ValueError(f"Unknown provider: {provider_name}")
|
|
166
|
-
|
|
167
|
-
key = provider_keys[provider_name]
|
|
168
|
-
return self.update_field(key, model)
|
|
169
|
-
|
|
170
|
-
def set_api_key(self, provider_name: str, api_key: str) -> Optional[Path]:
|
|
171
|
-
"""Set API key for a specific provider.
|
|
172
|
-
|
|
173
|
-
Args:
|
|
174
|
-
provider_name: Provider name (e.g., 'openrouter', 'glm', 'openai')
|
|
175
|
-
api_key: API key to set
|
|
176
|
-
|
|
177
|
-
Returns:
|
|
178
|
-
Backup path if backup was created, None otherwise
|
|
179
|
-
"""
|
|
180
|
-
# Map provider names to their config keys
|
|
181
|
-
provider_keys = {
|
|
182
|
-
'openrouter': 'OPENROUTER_API_KEY',
|
|
183
|
-
'bone': 'BONE_PROXY_API_KEY',
|
|
184
|
-
'codex': 'CODEX_PLAN_API_KEY',
|
|
185
|
-
'glm': 'GLM_API_KEY',
|
|
186
|
-
'glm_plan': 'GLM_PLAN_API_KEY',
|
|
187
|
-
'openai': 'OPENAI_API_KEY',
|
|
188
|
-
'gemini': 'GEMINI_API_KEY',
|
|
189
|
-
'minimax': 'MINIMAX_API_KEY',
|
|
190
|
-
'minimax_plan': 'MINIMAX_PLAN_API_KEY',
|
|
191
|
-
'anthropic': 'ANTHROPIC_API_KEY',
|
|
192
|
-
'kimi': 'KIMI_API_KEY'
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if provider_name not in provider_keys:
|
|
196
|
-
raise ValueError(f"Unknown provider: {provider_name}")
|
|
197
|
-
|
|
198
|
-
key = provider_keys[provider_name]
|
|
199
|
-
return self.update_field(key, api_key)
|
|
200
|
-
|
|
201
|
-
def get_model_price(self, model_name: str) -> Dict[str, float]:
|
|
202
|
-
"""Get pricing for a specific model.
|
|
203
|
-
|
|
204
|
-
Args:
|
|
205
|
-
model_name: Model name (e.g., 'minimax/minimax-m2.5', 'GLM-4.7')
|
|
206
|
-
|
|
207
|
-
Returns:
|
|
208
|
-
Dict with 'in' and 'out' cost values per 1M tokens
|
|
209
|
-
"""
|
|
210
|
-
config_data = self.load()
|
|
211
|
-
return self._extract_model_pricing(model_name, config=config_data)
|
|
212
|
-
|
|
213
|
-
def set_model_price(self, model_name: str, cost_in: float, cost_out: float) -> Optional[Path]:
|
|
214
|
-
"""Set pricing for a specific model.
|
|
215
|
-
|
|
216
|
-
Args:
|
|
217
|
-
model_name: Model name (e.g., 'minimax/minimax-m2.5', 'GLM-4.7')
|
|
218
|
-
cost_in: Cost per 1M input tokens
|
|
219
|
-
cost_out: Cost per 1M output tokens
|
|
220
|
-
|
|
221
|
-
Returns:
|
|
222
|
-
Backup path if backup was created, None otherwise
|
|
223
|
-
"""
|
|
224
|
-
config_data = self.load(force_reload=True)
|
|
225
|
-
|
|
226
|
-
if 'MODEL_PRICES' not in config_data:
|
|
227
|
-
config_data['MODEL_PRICES'] = {}
|
|
228
|
-
|
|
229
|
-
config_data['MODEL_PRICES'][model_name] = {
|
|
230
|
-
'cost_in': cost_in,
|
|
231
|
-
'cost_out': cost_out
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
return self.save(config_data, create_backup=False)
|
|
235
|
-
|
|
236
|
-
def list_model_prices(self) -> Dict[str, Dict[str, float]]:
|
|
237
|
-
"""Get all model-specific pricing.
|
|
238
|
-
|
|
239
|
-
Returns:
|
|
240
|
-
Dict mapping model names to their pricing (cost_in/cost_out per 1M tokens)
|
|
241
|
-
"""
|
|
242
|
-
config_data = self.load()
|
|
243
|
-
return config_data.get('MODEL_PRICES', {})
|
|
244
|
-
|
|
245
|
-
def delete_model_price(self, model_name: str) -> Optional[Path]:
|
|
246
|
-
"""Delete pricing for a specific model.
|
|
247
|
-
|
|
248
|
-
Args:
|
|
249
|
-
model_name: Model name to remove from pricing
|
|
250
|
-
|
|
251
|
-
Returns:
|
|
252
|
-
Backup path if backup was created, None otherwise
|
|
253
|
-
"""
|
|
254
|
-
config_data = self.load(force_reload=True)
|
|
255
|
-
|
|
256
|
-
if 'MODEL_PRICES' in config_data and model_name in config_data['MODEL_PRICES']:
|
|
257
|
-
del config_data['MODEL_PRICES'][model_name]
|
|
258
|
-
return self.save(config_data, create_backup=False)
|
|
259
|
-
|
|
260
|
-
return None
|