bone-agent 1.3.1 → 1.3.3
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 +2 -2
- package/config.yaml.example +8 -0
- 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 +36 -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/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/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 +9 -78
- package/src/core/chat_manager.py +120 -108
- package/src/core/config_manager.py +6 -0
- package/src/core/cron.py +57 -2
- package/src/core/memory.py +3 -90
- package/src/llm/config.py +28 -2
- package/src/llm/prompts.py +251 -497
- package/src/llm/providers.py +25 -6
- package/src/llm/token_tracker.py +17 -1
- package/src/tools/edit.py +8 -6
- package/src/tools/helpers/path_resolver.py +18 -12
- package/src/tools/rg_search.py +97 -30
- package/src/tools/select_option.py +12 -5
- package/src/ui/commands.py +120 -5
- package/src/ui/displays.py +1 -0
- package/src/ui/main.py +1 -0
- package/src/utils/settings.py +19 -2
- package/src/utils/user_message_logger.py +120 -0
package/src/core/memory.py
CHANGED
|
@@ -4,8 +4,9 @@ Two-layer persistent memory:
|
|
|
4
4
|
- User memory (global): ~/.bone/user_memory.md
|
|
5
5
|
- Project memory (per-repo): {repo_root}/.bone/agents.md
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
Memory files are read-only during conversations — loaded into the system prompt
|
|
8
|
+
for context but never written inline. All writes happen through the dream cron job,
|
|
9
|
+
which consolidates user messages into focused memories nightly.
|
|
9
10
|
"""
|
|
10
11
|
|
|
11
12
|
import logging
|
|
@@ -16,8 +17,6 @@ logger = logging.getLogger(__name__)
|
|
|
16
17
|
|
|
17
18
|
# Capacity constants (prompt-enforced, no code enforcement)
|
|
18
19
|
CHAR_LIMIT = 1500 # suggested chars per layer (~500 tokens)
|
|
19
|
-
SECTION_LIMIT = 8 # suggested max sections per layer
|
|
20
|
-
ENTRY_LIMIT = 20 # suggested max entries per section
|
|
21
20
|
|
|
22
21
|
|
|
23
22
|
class MemoryManager:
|
|
@@ -80,17 +79,6 @@ class MemoryManager:
|
|
|
80
79
|
"""Read and return project memory file content. Returns empty string if missing."""
|
|
81
80
|
return self._read_file(self.project_memory_path)
|
|
82
81
|
|
|
83
|
-
def load_all(self) -> str:
|
|
84
|
-
"""Load both layers, combined for prompt injection."""
|
|
85
|
-
parts = []
|
|
86
|
-
user = self.load_user_memory()
|
|
87
|
-
project = self.load_project_memory()
|
|
88
|
-
if user.strip():
|
|
89
|
-
parts.append(user.strip())
|
|
90
|
-
if project.strip():
|
|
91
|
-
parts.append(project.strip())
|
|
92
|
-
return "\n\n".join(parts)
|
|
93
|
-
|
|
94
82
|
def get_user_usage(self) -> dict:
|
|
95
83
|
"""Return {chars_used, chars_limit} for user memory."""
|
|
96
84
|
content = self.load_user_memory()
|
|
@@ -101,81 +89,6 @@ class MemoryManager:
|
|
|
101
89
|
content = self.load_project_memory()
|
|
102
90
|
return {"chars_used": len(content), "chars_limit": CHAR_LIMIT}
|
|
103
91
|
|
|
104
|
-
def get_prompt_section(self) -> str:
|
|
105
|
-
"""Build the full memory system prompt section.
|
|
106
|
-
|
|
107
|
-
Includes:
|
|
108
|
-
- Guidelines text with resolved file paths
|
|
109
|
-
- Capacity headers and memory content (if files have entries beyond headers)
|
|
110
|
-
|
|
111
|
-
Returns:
|
|
112
|
-
Complete prompt section string. Includes guidelines even when
|
|
113
|
-
memory files are empty (just headers). Returns guidelines with
|
|
114
|
-
placeholder paths if no MemoryManager instance exists.
|
|
115
|
-
"""
|
|
116
|
-
user_path = str(self.user_memory_path)
|
|
117
|
-
project_path = str(self.project_memory_path)
|
|
118
|
-
|
|
119
|
-
lines = [
|
|
120
|
-
"## Memory System",
|
|
121
|
-
"",
|
|
122
|
-
"You have a two-layer memory system that persists across conversations:",
|
|
123
|
-
f"- User memory (global): {user_path} — preferences, identity, work patterns",
|
|
124
|
-
f"- Project memory (per-repo): {project_path} — context, conventions, decisions, current work",
|
|
125
|
-
"",
|
|
126
|
-
"Both memory layers are loaded into this prompt at conversation start. "
|
|
127
|
-
"You can already see all memories below.",
|
|
128
|
-
"",
|
|
129
|
-
"To save information, use `edit_file` to write directly to the memory files. "
|
|
130
|
-
"These edits are auto-approved and run silently.",
|
|
131
|
-
"Add a timestamp in parentheses: `*(YYYY-MM-DD)*`",
|
|
132
|
-
"",
|
|
133
|
-
"### Save these (proactively):",
|
|
134
|
-
"- User preferences: \"I prefer TypeScript over JavaScript\" → user memory",
|
|
135
|
-
"- Environment facts: \"This project uses Python 3.11 with pytest\" → project memory",
|
|
136
|
-
"- Corrections: \"Don't use sudo for docker, user is in docker group\" → project memory",
|
|
137
|
-
"- Conventions: \"Project uses tabs, 120-char line width\" → project memory",
|
|
138
|
-
"- Completed work: \"Migrated database schema on 2026-04-20\" → project memory",
|
|
139
|
-
"- Explicit requests: \"Remember that my API key rotation happens monthly\" → user memory",
|
|
140
|
-
"",
|
|
141
|
-
"### Skip these:",
|
|
142
|
-
"- Trivial/obvious info: \"User asked about Python\" — too vague to be useful",
|
|
143
|
-
"- Easily re-discovered facts: \"Python 3.12 supports f-string nesting\" — can web search this",
|
|
144
|
-
"- Raw data dumps: Large code blocks, log files, data tables — too big for memory",
|
|
145
|
-
"- Session-specific ephemera: Temporary file paths, one-off debugging context",
|
|
146
|
-
"- Information already in agents.md or other context files",
|
|
147
|
-
"",
|
|
148
|
-
"Keep memories concise and information-dense. Use the section that best fits the information.",
|
|
149
|
-
"To update a memory, edit the entry in place with a new timestamp.",
|
|
150
|
-
"To remove a memory, delete the line.",
|
|
151
|
-
f"Stay under {CHAR_LIMIT} chars per file (~500 tokens). "
|
|
152
|
-
f"When above 80% ({int(CHAR_LIMIT * 0.8)} chars), consolidate older entries before adding new ones.",
|
|
153
|
-
]
|
|
154
|
-
|
|
155
|
-
# Add capacity headers and memory content if files have real content
|
|
156
|
-
user_content = self.load_user_memory()
|
|
157
|
-
user_usage = self.get_user_usage()
|
|
158
|
-
# Only show block if file has more than just the header
|
|
159
|
-
if self._has_entries(user_content):
|
|
160
|
-
pct = user_usage["chars_used"] * 100 // user_usage["chars_limit"]
|
|
161
|
-
lines.extend([
|
|
162
|
-
"",
|
|
163
|
-
f"USER MEMORY [{pct}% — {user_usage['chars_used']}/{user_usage['chars_limit']} chars]",
|
|
164
|
-
user_content.strip(),
|
|
165
|
-
])
|
|
166
|
-
|
|
167
|
-
project_content = self.load_project_memory()
|
|
168
|
-
project_usage = self.get_project_usage()
|
|
169
|
-
if self._has_entries(project_content):
|
|
170
|
-
pct = project_usage["chars_used"] * 100 // project_usage["chars_limit"]
|
|
171
|
-
lines.extend([
|
|
172
|
-
"",
|
|
173
|
-
f"PROJECT MEMORY [{pct}% — {project_usage['chars_used']}/{project_usage['chars_limit']} chars]",
|
|
174
|
-
project_content.strip(),
|
|
175
|
-
])
|
|
176
|
-
|
|
177
|
-
return "\n".join(lines)
|
|
178
|
-
|
|
179
92
|
# ---- Private helpers ----
|
|
180
93
|
|
|
181
94
|
@staticmethod
|
package/src/llm/config.py
CHANGED
|
@@ -354,7 +354,7 @@ def reload_config():
|
|
|
354
354
|
|
|
355
355
|
Note: This is a manual operation - call after config changes.
|
|
356
356
|
"""
|
|
357
|
-
global _CONFIG, _provider_registry_cache, _cached_provider, PROVIDER_REGISTRY, LLM_PROVIDER, STATUS_BAR_SETTINGS
|
|
357
|
+
global _CONFIG, _provider_registry_cache, _cached_provider, PROVIDER_REGISTRY, LLM_PROVIDER, STATUS_BAR_SETTINGS, MEMORY_SETTINGS
|
|
358
358
|
_CONFIG = _load_config()
|
|
359
359
|
_provider_registry_cache = None
|
|
360
360
|
_cached_provider = None
|
|
@@ -363,6 +363,8 @@ def reload_config():
|
|
|
363
363
|
LLM_PROVIDER = _get_provider()
|
|
364
364
|
# Rebuild status bar settings
|
|
365
365
|
STATUS_BAR_SETTINGS = _build_status_bar_settings()
|
|
366
|
+
# Rebuild memory settings
|
|
367
|
+
MEMORY_SETTINGS = _build_memory_settings()
|
|
366
368
|
|
|
367
369
|
|
|
368
370
|
def _build_status_bar_settings():
|
|
@@ -377,8 +379,27 @@ def _build_status_bar_settings():
|
|
|
377
379
|
}
|
|
378
380
|
|
|
379
381
|
|
|
382
|
+
def _build_memory_settings():
|
|
383
|
+
"""Build MEMORY_SETTINGS dict from current _CONFIG."""
|
|
384
|
+
ms = _CONFIG.get("MEMORY_SETTINGS", {})
|
|
385
|
+
return {
|
|
386
|
+
"enabled": ms.get("enabled", True),
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def update_memory_settings(settings_dict):
|
|
391
|
+
"""Update MEMORY_SETTINGS at runtime.
|
|
392
|
+
|
|
393
|
+
Returns:
|
|
394
|
+
Updated MEMORY_SETTINGS dict
|
|
395
|
+
"""
|
|
396
|
+
global MEMORY_SETTINGS
|
|
397
|
+
MEMORY_SETTINGS.update(settings_dict)
|
|
398
|
+
return MEMORY_SETTINGS
|
|
399
|
+
|
|
400
|
+
|
|
380
401
|
def update_status_bar_settings(settings_dict):
|
|
381
|
-
"""Update STATUS_BAR_SETTINGS at runtime
|
|
402
|
+
"""Update STATUS_BAR_SETTINGS at runtime.
|
|
382
403
|
|
|
383
404
|
Args:
|
|
384
405
|
settings_dict: Dict of settings to update (e.g., {"show_cost": False})
|
|
@@ -426,6 +447,8 @@ __all__ = [
|
|
|
426
447
|
"reload_config",
|
|
427
448
|
"STATUS_BAR_SETTINGS",
|
|
428
449
|
"update_status_bar_settings",
|
|
450
|
+
"MEMORY_SETTINGS",
|
|
451
|
+
"update_memory_settings",
|
|
429
452
|
]
|
|
430
453
|
|
|
431
454
|
|
|
@@ -445,6 +468,9 @@ WEB_SEARCH_REQUIRE_CONFIRMATION = False
|
|
|
445
468
|
# Status bar configuration
|
|
446
469
|
STATUS_BAR_SETTINGS = _build_status_bar_settings()
|
|
447
470
|
|
|
471
|
+
# Memory configuration
|
|
472
|
+
MEMORY_SETTINGS = _build_memory_settings()
|
|
473
|
+
|
|
448
474
|
# Tool approval modes
|
|
449
475
|
APPROVE_MODES = ("safe", "accept_edits", "danger")
|
|
450
476
|
CYCLEABLE_APPROVE_MODES = ("safe", "accept_edits")
|