aru-code 0.14.0__tar.gz → 0.14.1__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.
- {aru_code-0.14.0/aru_code.egg-info → aru_code-0.14.1}/PKG-INFO +1 -1
- aru_code-0.14.1/aru/__init__.py +1 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/context.py +19 -13
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/runner.py +3 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/tools/codebase.py +6 -6
- {aru_code-0.14.0 → aru_code-0.14.1/aru_code.egg-info}/PKG-INFO +1 -1
- {aru_code-0.14.0 → aru_code-0.14.1}/pyproject.toml +1 -1
- aru_code-0.14.0/aru/__init__.py +0 -1
- {aru_code-0.14.0 → aru_code-0.14.1}/LICENSE +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/README.md +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/agent_factory.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/agents/__init__.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/agents/base.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/agents/executor.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/agents/planner.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/cli.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/commands.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/completers.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/config.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/display.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/permissions.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/providers.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/runtime.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/session.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/tools/__init__.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/tools/ast_tools.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/tools/gitignore.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/tools/mcp_client.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/tools/ranker.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru/tools/tasklist.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru_code.egg-info/SOURCES.txt +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru_code.egg-info/dependency_links.txt +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru_code.egg-info/entry_points.txt +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru_code.egg-info/requires.txt +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/aru_code.egg-info/top_level.txt +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/setup.cfg +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_agents_base.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_ast_tools.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_cli.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_cli_advanced.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_cli_base.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_cli_completers.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_cli_new.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_cli_run_cli.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_cli_session.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_cli_shell.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_codebase.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_config.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_context.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_executor.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_gitignore.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_main.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_mcp_client.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_permissions.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_planner.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_providers.py +0 -0
- {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_ranker.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.14.1"
|
|
@@ -11,7 +11,7 @@ from __future__ import annotations
|
|
|
11
11
|
# ── Constants ──────────────────────────────────────────────────────
|
|
12
12
|
|
|
13
13
|
# Pruning: minimum chars that must be freeable to justify a prune pass
|
|
14
|
-
PRUNE_MINIMUM_CHARS =
|
|
14
|
+
PRUNE_MINIMUM_CHARS = 12_000 # ~3K tokens (lower = prune sooner)
|
|
15
15
|
# Placeholder that replaces evicted content
|
|
16
16
|
PRUNED_PLACEHOLDER = "[previous output cleared to save context]"
|
|
17
17
|
# User messages larger than this threshold are truncated when outside protection window
|
|
@@ -24,16 +24,18 @@ PRUNE_PROTECT_TURNS = 2
|
|
|
24
24
|
PRUNE_PROTECTED_MARKERS = {"[SubAgent-", "delegate_task"}
|
|
25
25
|
|
|
26
26
|
# Truncation: universal limits for any tool output
|
|
27
|
-
TRUNCATE_MAX_LINES =
|
|
28
|
-
TRUNCATE_MAX_BYTES =
|
|
29
|
-
TRUNCATE_KEEP_START =
|
|
30
|
-
TRUNCATE_KEEP_END =
|
|
27
|
+
TRUNCATE_MAX_LINES = 300
|
|
28
|
+
TRUNCATE_MAX_BYTES = 15 * 1024 # 15 KB (was 20KB — tighter to prevent context bloat)
|
|
29
|
+
TRUNCATE_KEEP_START = 200 # lines to keep from the start
|
|
30
|
+
TRUNCATE_KEEP_END = 60 # lines to keep from the end
|
|
31
31
|
TRUNCATE_MAX_LINE_LENGTH = 2000 # chars per individual line (prevents minified files)
|
|
32
32
|
|
|
33
33
|
# Compaction: trigger when per-run input tokens exceed this fraction of model limit
|
|
34
|
-
COMPACTION_THRESHOLD_RATIO = 0.85
|
|
34
|
+
COMPACTION_THRESHOLD_RATIO = 0.70 # was 0.85 — compact earlier to avoid hitting limits
|
|
35
35
|
# Compaction: target post-compaction size as fraction of model context limit
|
|
36
36
|
COMPACTION_TARGET_RATIO = 0.15
|
|
37
|
+
# Compaction: reserve buffer for the compaction process itself (like OpenCode's 20K)
|
|
38
|
+
COMPACTION_BUFFER_TOKENS = 20_000
|
|
37
39
|
# Default model context limits (input tokens)
|
|
38
40
|
MODEL_CONTEXT_LIMITS: dict[str, int] = {
|
|
39
41
|
# Anthropic
|
|
@@ -103,13 +105,13 @@ def _get_prune_protect_chars(model_id: str = "default") -> int:
|
|
|
103
105
|
"""Scale protection window based on model context size.
|
|
104
106
|
|
|
105
107
|
Larger models get more protection; smaller models prune more aggressively
|
|
106
|
-
to
|
|
108
|
+
to prevent context overflow. Returns ~7% of the model's context in chars.
|
|
107
109
|
"""
|
|
108
110
|
limit = MODEL_CONTEXT_LIMITS.get(model_id, MODEL_CONTEXT_LIMITS["default"])
|
|
109
|
-
# ~
|
|
110
|
-
protect = int(limit * 0.
|
|
111
|
-
# Clamp between
|
|
112
|
-
return max(
|
|
111
|
+
# ~4 chars per token, protect ~7% of context (was 10% — tighter budget)
|
|
112
|
+
protect = int(limit * 0.07 * 4)
|
|
113
|
+
# Clamp between 15K (minimum usable) and 60K (diminishing returns)
|
|
114
|
+
return max(15_000, min(protect, 60_000))
|
|
113
115
|
|
|
114
116
|
|
|
115
117
|
def prune_history(
|
|
@@ -278,7 +280,10 @@ def should_compact(
|
|
|
278
280
|
history_or_tokens: int | list[dict[str, str]],
|
|
279
281
|
model_id: str = "default",
|
|
280
282
|
) -> bool:
|
|
281
|
-
"""Check if the conversation should be compacted
|
|
283
|
+
"""Check if the conversation should be compacted.
|
|
284
|
+
|
|
285
|
+
Uses OpenCode's approach: usable = model_limit - buffer, then
|
|
286
|
+
trigger when tokens >= usable * threshold_ratio.
|
|
282
287
|
|
|
283
288
|
Accepts either an estimated token count (int) or the history list
|
|
284
289
|
(from which tokens are estimated via char count).
|
|
@@ -288,7 +293,8 @@ def should_compact(
|
|
|
288
293
|
else:
|
|
289
294
|
tokens = history_or_tokens
|
|
290
295
|
limit = MODEL_CONTEXT_LIMITS.get(model_id, MODEL_CONTEXT_LIMITS["default"])
|
|
291
|
-
|
|
296
|
+
usable = limit - COMPACTION_BUFFER_TOKENS
|
|
297
|
+
threshold = int(usable * COMPACTION_THRESHOLD_RATIO)
|
|
292
298
|
return tokens >= threshold
|
|
293
299
|
|
|
294
300
|
|
|
@@ -249,12 +249,15 @@ async def run_agent_capture(agent, message: str, session=None, lightweight: bool
|
|
|
249
249
|
run_input_tokens = getattr(run_output.metrics, "input_tokens", 0) or 0
|
|
250
250
|
if should_compact(run_input_tokens, session.model_id):
|
|
251
251
|
try:
|
|
252
|
+
# Always prune first to shrink history before compaction
|
|
253
|
+
session.history = prune_history(session.history, model_id=session.model_id)
|
|
252
254
|
session.history = await compact_conversation(
|
|
253
255
|
session.history, session.model_ref, session.plan_task,
|
|
254
256
|
model_id=session.model_id,
|
|
255
257
|
)
|
|
256
258
|
console.print("[dim]Context compacted to save tokens.[/dim]")
|
|
257
259
|
except Exception:
|
|
260
|
+
# Even if compaction fails, keep the pruned history
|
|
258
261
|
pass
|
|
259
262
|
|
|
260
263
|
final_content = accumulated or final_content
|
|
@@ -54,23 +54,23 @@ def _format_diff(old_string: str, new_string: str) -> Group:
|
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
# Hard ceiling per tool result (~
|
|
58
|
-
_READ_HARD_CAP =
|
|
57
|
+
# Hard ceiling per tool result (~10K tokens). Even max_size=0 respects this per chunk.
|
|
58
|
+
_READ_HARD_CAP = 40_000 # bytes (was 60K — tighter to protect context)
|
|
59
59
|
|
|
60
60
|
def clear_read_cache():
|
|
61
61
|
"""Clear the read cache. Call after file mutations to avoid stale data."""
|
|
62
62
|
get_ctx().read_cache.clear()
|
|
63
63
|
|
|
64
64
|
|
|
65
|
-
def read_file(file_path: str, start_line: int = 0, end_line: int = 0, max_size: int =
|
|
65
|
+
def read_file(file_path: str, start_line: int = 0, end_line: int = 0, max_size: int = 12_000) -> str:
|
|
66
66
|
"""Read file contents. Returns chunked output for large files.
|
|
67
67
|
|
|
68
68
|
Args:
|
|
69
69
|
file_path: Path to the file (absolute or relative).
|
|
70
70
|
start_line: First line (1-indexed, inclusive). 0 = beginning.
|
|
71
71
|
end_line: Last line (1-indexed, inclusive). 0 = end.
|
|
72
|
-
max_size: Max bytes before truncation. Default
|
|
73
|
-
Set to 0 to read the full file in chunks — each chunk up to ~
|
|
72
|
+
max_size: Max bytes before truncation. Default 12KB.
|
|
73
|
+
Set to 0 to read the full file in chunks — each chunk up to ~40KB.
|
|
74
74
|
The first chunk includes a continuation hint so you can call again
|
|
75
75
|
with start_line to get the next chunk.
|
|
76
76
|
"""
|
|
@@ -204,7 +204,7 @@ async def read_file_smart(file_path: str, query: str) -> str:
|
|
|
204
204
|
query: The specific question you want answered about this file.
|
|
205
205
|
"""
|
|
206
206
|
# Read raw content first (reuse existing read_file logic)
|
|
207
|
-
raw = read_file(file_path, max_size=
|
|
207
|
+
raw = read_file(file_path, max_size=15_000)
|
|
208
208
|
|
|
209
209
|
if raw.startswith("Error:"):
|
|
210
210
|
return raw
|
aru_code-0.14.0/aru/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.14.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|