bone-agent 1.3.2 → 1.4.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/README.md +19 -2
- package/config.yaml.example +13 -2
- package/package.json +3 -2
- package/prompts/main/ask_questions.md +31 -0
- package/prompts/main/batch_independent_calls.md +5 -0
- package/prompts/main/casual_interactions.md +11 -0
- package/prompts/main/code_references.md +8 -0
- package/prompts/main/communication_style.md +12 -0
- package/prompts/main/context_reliability.md +12 -0
- package/prompts/main/conversational_tool_calling.md +15 -0
- package/prompts/main/dream.md +50 -0
- package/prompts/main/editing_pattern.md +13 -0
- package/prompts/main/error_handling.md +6 -0
- package/prompts/main/exploration_pattern.md +21 -0
- package/prompts/main/intro.md +1 -0
- package/prompts/main/obsidian.md +16 -0
- package/prompts/main/obsidian_project.md +79 -0
- package/prompts/main/professional_objectivity.md +3 -0
- package/prompts/main/skills.md +3 -0
- package/prompts/main/targeted_searching.md +10 -0
- package/prompts/main/task_lists_pattern.md +8 -0
- package/prompts/main/temp_folder.md +9 -0
- package/prompts/main/think_before_acting.md +10 -0
- package/prompts/main/tone_and_style.md +4 -0
- package/prompts/main/tool_preferences.md +24 -0
- package/prompts/main/trust_subagent_context.md +21 -0
- package/prompts/main/when_to_use_sub_agent.md +7 -0
- package/prompts/micro/ask_questions.md +1 -0
- package/prompts/micro/batch_independent_calls.md +1 -0
- package/prompts/micro/casual_interactions.md +1 -0
- package/prompts/micro/code_references.md +1 -0
- package/prompts/micro/communication_style.md +1 -0
- package/prompts/micro/context_reliability.md +1 -0
- package/prompts/micro/conversational_tool_calling.md +1 -0
- package/prompts/micro/editing_pattern.md +1 -0
- package/prompts/micro/error_handling.md +1 -0
- package/prompts/micro/exploration_pattern.md +1 -0
- package/prompts/micro/intro.md +1 -0
- package/prompts/micro/obsidian.md +4 -0
- package/prompts/micro/obsidian_project.md +5 -0
- package/prompts/micro/professional_objectivity.md +1 -0
- package/prompts/micro/skills.md +1 -0
- package/prompts/micro/targeted_searching.md +1 -0
- package/prompts/micro/task_lists_pattern.md +1 -0
- package/prompts/micro/temp_folder.md +1 -0
- package/prompts/micro/think_before_acting.md +5 -0
- package/prompts/micro/tone_and_style.md +1 -0
- package/prompts/micro/tool_preferences.md +1 -0
- package/prompts/micro/trust_subagent_context.md +1 -0
- package/prompts/micro/when_to_use_sub_agent.md +1 -0
- package/src/core/agentic.py +134 -106
- package/src/core/chat_manager.py +60 -12
- package/src/core/config_manager.py +14 -1
- package/src/core/cron.py +57 -6
- package/src/core/memory.py +3 -90
- package/src/core/metadata.py +75 -0
- package/src/core/skills.py +463 -0
- package/src/core/sub_agent.py +93 -43
- package/src/core/tool_feedback.py +87 -76
- package/src/llm/client.py +7 -2
- package/src/llm/codex_provider.py +350 -0
- package/src/llm/config.py +74 -4
- package/src/llm/prompts.py +261 -502
- package/src/llm/providers.py +28 -7
- package/src/llm/token_tracker.py +32 -1
- package/src/tools/__init__.py +24 -85
- package/src/tools/create_file.py +1 -1
- package/src/tools/directory.py +1 -1
- package/src/tools/edit.py +13 -7
- package/src/tools/file_reader.py +1 -1
- package/src/tools/helpers/__init__.py +1 -7
- package/src/tools/helpers/base.py +65 -16
- package/src/tools/helpers/loader.py +2 -88
- package/src/tools/helpers/path_resolver.py +70 -13
- package/src/tools/helpers/plugin_manifest.py +99 -70
- package/src/tools/review_sub_agent.py +2 -1
- package/src/tools/rg_search.py +119 -35
- package/src/tools/search_plugins.py +140 -72
- package/src/tools/shell.py +3 -3
- package/src/ui/commands.py +470 -33
- package/src/ui/displays.py +27 -1
- package/src/ui/main.py +1 -4
- package/src/ui/tool_confirmation.py +16 -5
- package/src/utils/editor.py +88 -39
- package/src/utils/settings.py +25 -4
- package/src/utils/user_message_logger.py +120 -0
- package/src/utils/validation.py +10 -0
|
@@ -1,38 +1,41 @@
|
|
|
1
|
-
"""search_plugins core tool for on-demand
|
|
1
|
+
"""search_plugins core tool for on-demand capability discovery.
|
|
2
2
|
|
|
3
3
|
This tool lets the LLM agent search for available plugin tools and
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
stored skills, then explicitly activate plugins or load skills through
|
|
5
|
+
the same entrypoint. Plugin schemas are not sent by default to avoid
|
|
6
|
+
context bloat — they are only included after activation.
|
|
6
7
|
"""
|
|
7
8
|
|
|
8
|
-
from typing import List, Optional
|
|
9
|
-
from pathlib import Path
|
|
10
|
-
|
|
11
9
|
from tools.helpers.base import tool, ToolRegistry, TERMINAL_NONE
|
|
12
10
|
|
|
11
|
+
HEADER_MATCHES = "Capability matches for: "
|
|
12
|
+
HEADER_ALL = "All available capabilities"
|
|
13
|
+
|
|
13
14
|
|
|
14
15
|
@tool(
|
|
15
16
|
name="search_plugins",
|
|
16
17
|
description=(
|
|
17
|
-
"Search for available plugin tools that can help
|
|
18
|
-
"
|
|
19
|
-
"to discover and activate them.
|
|
20
|
-
"
|
|
21
|
-
"available in your
|
|
18
|
+
"Search for available plugin tools and saved skills that can help "
|
|
19
|
+
"with your task. Plugins are NOT in your available tools by default "
|
|
20
|
+
"— use this to discover and activate them. Skills can also be loaded "
|
|
21
|
+
"through this same tool by passing explicit capability names in 'load'. "
|
|
22
|
+
"Once a plugin is activated, its full schema will be available in your "
|
|
23
|
+
"next response."
|
|
22
24
|
),
|
|
23
25
|
parameters={
|
|
24
26
|
"type": "object",
|
|
25
27
|
"properties": {
|
|
26
28
|
"query": {
|
|
27
29
|
"type": "string",
|
|
28
|
-
"description": "Search query describing what you need (e.g., 'send email', 'query database', 'http request')"
|
|
30
|
+
"description": "Search query describing what you need (e.g., 'send email', 'query database', 'http request'). Omit to list all available plugins and skills."
|
|
29
31
|
},
|
|
30
|
-
"
|
|
31
|
-
"type": "
|
|
32
|
-
"
|
|
32
|
+
"load": {
|
|
33
|
+
"type": "array",
|
|
34
|
+
"items": {"type": "string"},
|
|
35
|
+
"description": "Optional list of exact capability names from the current search results to activate or load. Plugins are activated; skills are injected into the current chat."
|
|
33
36
|
}
|
|
34
37
|
},
|
|
35
|
-
"required": [
|
|
38
|
+
"required": []
|
|
36
39
|
},
|
|
37
40
|
requires_approval=False,
|
|
38
41
|
terminal_policy=TERMINAL_NONE,
|
|
@@ -41,69 +44,134 @@ from tools.helpers.base import tool, ToolRegistry, TERMINAL_NONE
|
|
|
41
44
|
category="core"
|
|
42
45
|
)
|
|
43
46
|
def search_plugins(
|
|
44
|
-
query: str,
|
|
45
|
-
|
|
47
|
+
query: str = "",
|
|
48
|
+
load: list[str] | None = None,
|
|
49
|
+
chat_manager=None,
|
|
46
50
|
) -> str:
|
|
47
|
-
"""Search
|
|
48
|
-
|
|
49
|
-
Args:
|
|
50
|
-
query: Search query describing the needed capability
|
|
51
|
-
category: Optional category filter
|
|
51
|
+
"""Search discoverable capabilities and optionally activate/load selected matches.
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"""
|
|
53
|
+
When using `load`, `query` must be provided so selections come from the current search results."""
|
|
54
|
+
from core.skills import SkillError, activate_skill, validate_skill_name
|
|
56
55
|
from tools.helpers.plugin_manifest import plugin_manifest
|
|
57
56
|
|
|
58
|
-
# Check if any core tool matches the query — early return
|
|
59
57
|
core_tools = ToolRegistry.get_all(include_plugins=False)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
#
|
|
70
|
-
|
|
58
|
+
core_tool_note = None
|
|
59
|
+
query = query.strip()
|
|
60
|
+
|
|
61
|
+
if load and not query:
|
|
62
|
+
return "\n".join([
|
|
63
|
+
"exit_code=1",
|
|
64
|
+
"Loading capabilities requires a query so selections come from the current search results.",
|
|
65
|
+
])
|
|
66
|
+
|
|
67
|
+
# No query → list everything
|
|
68
|
+
if not query:
|
|
69
|
+
matches = plugin_manifest.list_all_capabilities()
|
|
70
|
+
else:
|
|
71
|
+
query_lower = query.lower()
|
|
72
|
+
for ct in core_tools:
|
|
73
|
+
if query_lower == ct.name.lower():
|
|
74
|
+
core_tool_note = (
|
|
75
|
+
f"Core tool already available: {ct.name}\n"
|
|
76
|
+
f" {ct.description}"
|
|
77
|
+
)
|
|
78
|
+
break
|
|
79
|
+
|
|
80
|
+
matches = plugin_manifest.search_capabilities(query, max_results=10)
|
|
71
81
|
|
|
72
82
|
if not matches:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
f"exit_code=0\n"
|
|
79
|
-
f"No plugins found matching '{query}'.\n"
|
|
80
|
-
f"Available plugin categories: {cat_list}\n"
|
|
81
|
-
f"Total plugins in manifest: {plugin_manifest.plugin_count()}"
|
|
82
|
-
)
|
|
83
|
-
return (
|
|
84
|
-
f"exit_code=0\n"
|
|
85
|
-
f"No plugins found matching '{query}'. "
|
|
86
|
-
f"No plugins are currently registered in the manifest."
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
# Activate matched plugins in the registry
|
|
90
|
-
activated = []
|
|
91
|
-
already_active = []
|
|
92
|
-
for tool_def in matches:
|
|
93
|
-
if ToolRegistry.is_plugin_active(tool_def.name):
|
|
94
|
-
already_active.append(tool_def.name)
|
|
83
|
+
lines = ["exit_code=0"]
|
|
84
|
+
if core_tool_note:
|
|
85
|
+
lines.extend([core_tool_note, ""])
|
|
86
|
+
if query:
|
|
87
|
+
lines.append(f"No matches for: {query}")
|
|
95
88
|
else:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
89
|
+
lines.append("No plugins or skills available.")
|
|
90
|
+
return "\n".join(lines)
|
|
91
|
+
|
|
92
|
+
requested = [name for name in (load or []) if isinstance(name, str) and name.strip()]
|
|
93
|
+
requested_normalized = {name.strip().lower(): name.strip() for name in requested}
|
|
94
|
+
matched_by_name = {match.name.lower(): match for match in matches}
|
|
95
|
+
|
|
96
|
+
plugin_count = 0
|
|
97
|
+
skill_count = 0
|
|
98
|
+
loaded_plugins = []
|
|
99
|
+
loaded_skills = []
|
|
100
|
+
load_errors = []
|
|
101
|
+
|
|
102
|
+
for match in matches:
|
|
103
|
+
if match.kind == "plugin" and match.tool_def:
|
|
104
|
+
plugin_count += 1
|
|
105
|
+
if ToolRegistry.is_plugin_active(match.tool_def.name):
|
|
106
|
+
match.already_active = True
|
|
107
|
+
if match.name.lower() in requested_normalized and not match.already_active:
|
|
108
|
+
if ToolRegistry.activate_plugin(match.tool_def):
|
|
109
|
+
match.activated = True
|
|
110
|
+
loaded_plugins.append(match.name)
|
|
111
|
+
else:
|
|
112
|
+
load_errors.append(f"Plugin '{match.name}' is disabled. Enable it before loading.")
|
|
113
|
+
continue
|
|
114
|
+
skill_count += 1
|
|
115
|
+
if match.name.lower() in requested_normalized:
|
|
116
|
+
if chat_manager is None:
|
|
117
|
+
load_errors.append(f"Skill '{match.name}' cannot be loaded without an active chat.")
|
|
118
|
+
continue
|
|
119
|
+
try:
|
|
120
|
+
skill_name = validate_skill_name(match.name)
|
|
121
|
+
activate_skill(chat_manager, skill_name)
|
|
122
|
+
loaded_skills.append(skill_name)
|
|
123
|
+
except SkillError as exc:
|
|
124
|
+
load_errors.append(str(exc))
|
|
125
|
+
|
|
126
|
+
missing_requested = [
|
|
127
|
+
original_name
|
|
128
|
+
for normalized_name, original_name in requested_normalized.items()
|
|
129
|
+
if normalized_name not in matched_by_name
|
|
130
|
+
]
|
|
131
|
+
for missing in missing_requested:
|
|
132
|
+
load_errors.append(f"Capability '{missing}' was not found in the current search results.")
|
|
133
|
+
|
|
134
|
+
lines = ["exit_code=0"]
|
|
135
|
+
if core_tool_note:
|
|
136
|
+
lines.extend([core_tool_note, ""])
|
|
137
|
+
|
|
138
|
+
if query:
|
|
139
|
+
lines.extend([
|
|
140
|
+
f"{HEADER_MATCHES}{query}",
|
|
141
|
+
f"Results: {len(matches)} total ({plugin_count} plugin, {skill_count} skill)",
|
|
142
|
+
"",
|
|
143
|
+
])
|
|
144
|
+
else:
|
|
145
|
+
lines.extend([
|
|
146
|
+
HEADER_ALL,
|
|
147
|
+
f"Total: {len(matches)} ({plugin_count} plugin, {skill_count} skill)",
|
|
148
|
+
"",
|
|
149
|
+
])
|
|
150
|
+
|
|
151
|
+
for match in matches:
|
|
152
|
+
if match.kind == "plugin":
|
|
153
|
+
status = "disabled" if ToolRegistry.is_disabled(match.name) else "activated" if match.activated else "active" if match.already_active else "available"
|
|
154
|
+
lines.append(f"- {match.name}")
|
|
155
|
+
lines.append(" type: plugin")
|
|
156
|
+
lines.append(f" status: {status}")
|
|
157
|
+
lines.append(f" summary: {match.description}")
|
|
158
|
+
if match.tags:
|
|
159
|
+
lines.append(f" tags: {', '.join(match.tags)}")
|
|
160
|
+
continue
|
|
161
|
+
|
|
162
|
+
lines.append(f"- {match.name}")
|
|
163
|
+
lines.append(" type: skill")
|
|
164
|
+
lines.append(f" summary: {match.description}")
|
|
165
|
+
if match.tags:
|
|
166
|
+
lines.append(f" tags: {', '.join(match.tags)}")
|
|
167
|
+
|
|
168
|
+
if requested:
|
|
169
|
+
lines.append("")
|
|
170
|
+
if loaded_plugins:
|
|
171
|
+
lines.append(f"Activated plugins: {', '.join(loaded_plugins)}")
|
|
172
|
+
if loaded_skills:
|
|
173
|
+
lines.append(f"Loaded skills: {', '.join(loaded_skills)}")
|
|
174
|
+
if load_errors:
|
|
175
|
+
lines.append(f"Load issues: {'; '.join(load_errors)}")
|
|
108
176
|
|
|
109
177
|
return "\n".join(lines)
|
package/src/tools/shell.py
CHANGED
|
@@ -231,13 +231,13 @@ def run_shell_command(command, repo_root, rg_exe_path, console, debug_mode, giti
|
|
|
231
231
|
|
|
232
232
|
@tool(
|
|
233
233
|
name="execute_command",
|
|
234
|
-
description="Execute shell commands for git, system tasks, file ops, network, and package management. Runs from repo root. Use for git, ps, systemctl, rm, mv, cp, mkdir, ping, curl, wget, ssh, pacman, pip, npm, apt. Disallowed: rg, cat, ls, grep, find, head, tail, sed, awk, sort, uniq, wc, echo, touch, get-content, type, get-childitem, dir, new-item, set-content, add-content, tee. Use native tools instead.",
|
|
234
|
+
description="Execute shell commands for git, system tasks, file ops, network, and package management. Runs from repo root. Multi-line shell commands are supported and preserved exactly, including heredocs. Use for git, ps, systemctl, rm, mv, cp, mkdir, ping, curl, wget, ssh, pacman, pip, npm, apt. Disallowed: rg, cat, ls, grep, find, head, tail, sed, awk, sort, uniq, wc, echo, touch, get-content, type, get-childitem, dir, new-item, set-content, add-content, tee. Use native tools instead.",
|
|
235
235
|
parameters={
|
|
236
236
|
"type": "object",
|
|
237
237
|
"properties": {
|
|
238
238
|
"command": {
|
|
239
239
|
"type": "string",
|
|
240
|
-
"description": "
|
|
240
|
+
"description": "Shell command to execute from the repo root. May be a single-line command or a multi-line shell script/heredoc; newlines are preserved exactly."
|
|
241
241
|
},
|
|
242
242
|
"reason": {
|
|
243
243
|
"type": "string",
|
|
@@ -262,7 +262,7 @@ def execute_command(
|
|
|
262
262
|
"""Execute a shell command.
|
|
263
263
|
|
|
264
264
|
Args:
|
|
265
|
-
command: Command string to execute
|
|
265
|
+
command: Command string to execute. May contain newlines/heredocs; preserved exactly for shell execution.
|
|
266
266
|
repo_root: Repository root directory (injected by context)
|
|
267
267
|
rg_exe_path: Path to rg executable (injected by context)
|
|
268
268
|
console: Rich console for output (injected by context)
|