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.
Files changed (57) hide show
  1. {aru_code-0.14.0/aru_code.egg-info → aru_code-0.14.1}/PKG-INFO +1 -1
  2. aru_code-0.14.1/aru/__init__.py +1 -0
  3. {aru_code-0.14.0 → aru_code-0.14.1}/aru/context.py +19 -13
  4. {aru_code-0.14.0 → aru_code-0.14.1}/aru/runner.py +3 -0
  5. {aru_code-0.14.0 → aru_code-0.14.1}/aru/tools/codebase.py +6 -6
  6. {aru_code-0.14.0 → aru_code-0.14.1/aru_code.egg-info}/PKG-INFO +1 -1
  7. {aru_code-0.14.0 → aru_code-0.14.1}/pyproject.toml +1 -1
  8. aru_code-0.14.0/aru/__init__.py +0 -1
  9. {aru_code-0.14.0 → aru_code-0.14.1}/LICENSE +0 -0
  10. {aru_code-0.14.0 → aru_code-0.14.1}/README.md +0 -0
  11. {aru_code-0.14.0 → aru_code-0.14.1}/aru/agent_factory.py +0 -0
  12. {aru_code-0.14.0 → aru_code-0.14.1}/aru/agents/__init__.py +0 -0
  13. {aru_code-0.14.0 → aru_code-0.14.1}/aru/agents/base.py +0 -0
  14. {aru_code-0.14.0 → aru_code-0.14.1}/aru/agents/executor.py +0 -0
  15. {aru_code-0.14.0 → aru_code-0.14.1}/aru/agents/planner.py +0 -0
  16. {aru_code-0.14.0 → aru_code-0.14.1}/aru/cli.py +0 -0
  17. {aru_code-0.14.0 → aru_code-0.14.1}/aru/commands.py +0 -0
  18. {aru_code-0.14.0 → aru_code-0.14.1}/aru/completers.py +0 -0
  19. {aru_code-0.14.0 → aru_code-0.14.1}/aru/config.py +0 -0
  20. {aru_code-0.14.0 → aru_code-0.14.1}/aru/display.py +0 -0
  21. {aru_code-0.14.0 → aru_code-0.14.1}/aru/permissions.py +0 -0
  22. {aru_code-0.14.0 → aru_code-0.14.1}/aru/providers.py +0 -0
  23. {aru_code-0.14.0 → aru_code-0.14.1}/aru/runtime.py +0 -0
  24. {aru_code-0.14.0 → aru_code-0.14.1}/aru/session.py +0 -0
  25. {aru_code-0.14.0 → aru_code-0.14.1}/aru/tools/__init__.py +0 -0
  26. {aru_code-0.14.0 → aru_code-0.14.1}/aru/tools/ast_tools.py +0 -0
  27. {aru_code-0.14.0 → aru_code-0.14.1}/aru/tools/gitignore.py +0 -0
  28. {aru_code-0.14.0 → aru_code-0.14.1}/aru/tools/mcp_client.py +0 -0
  29. {aru_code-0.14.0 → aru_code-0.14.1}/aru/tools/ranker.py +0 -0
  30. {aru_code-0.14.0 → aru_code-0.14.1}/aru/tools/tasklist.py +0 -0
  31. {aru_code-0.14.0 → aru_code-0.14.1}/aru_code.egg-info/SOURCES.txt +0 -0
  32. {aru_code-0.14.0 → aru_code-0.14.1}/aru_code.egg-info/dependency_links.txt +0 -0
  33. {aru_code-0.14.0 → aru_code-0.14.1}/aru_code.egg-info/entry_points.txt +0 -0
  34. {aru_code-0.14.0 → aru_code-0.14.1}/aru_code.egg-info/requires.txt +0 -0
  35. {aru_code-0.14.0 → aru_code-0.14.1}/aru_code.egg-info/top_level.txt +0 -0
  36. {aru_code-0.14.0 → aru_code-0.14.1}/setup.cfg +0 -0
  37. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_agents_base.py +0 -0
  38. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_ast_tools.py +0 -0
  39. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_cli.py +0 -0
  40. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_cli_advanced.py +0 -0
  41. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_cli_base.py +0 -0
  42. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_cli_completers.py +0 -0
  43. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_cli_new.py +0 -0
  44. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_cli_run_cli.py +0 -0
  45. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_cli_session.py +0 -0
  46. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_cli_shell.py +0 -0
  47. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_codebase.py +0 -0
  48. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_config.py +0 -0
  49. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_context.py +0 -0
  50. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_executor.py +0 -0
  51. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_gitignore.py +0 -0
  52. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_main.py +0 -0
  53. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_mcp_client.py +0 -0
  54. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_permissions.py +0 -0
  55. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_planner.py +0 -0
  56. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_providers.py +0 -0
  57. {aru_code-0.14.0 → aru_code-0.14.1}/tests/test_ranker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aru-code
3
- Version: 0.14.0
3
+ Version: 0.14.1
4
4
  Summary: A Claude Code clone built with Agno agents
5
5
  Author-email: Estevao <estevaofon@gmail.com>
6
6
  License-Expression: MIT
@@ -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 = 20_000 # ~5.7K tokens
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 = 500
28
- TRUNCATE_MAX_BYTES = 20 * 1024 # 20 KB
29
- TRUNCATE_KEEP_START = 350 # lines to keep from the start
30
- TRUNCATE_KEEP_END = 100 # lines to keep from the 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 delay compaction. Returns ~10% of the model's context in chars (~3.5 chars/token).
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
- # ~3.5 chars per token, protect ~10% of context
110
- protect = int(limit * 0.10 * 3.5)
111
- # Clamp between 20K (minimum usable) and 80K (diminishing returns)
112
- return max(20_000, min(protect, 80_000))
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 (reactive, post-run).
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
- threshold = int(limit * COMPACTION_THRESHOLD_RATIO)
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 (~15K tokens). Even max_size=0 respects this per chunk.
58
- _READ_HARD_CAP = 60_000 # bytes
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 = 15_000) -> str:
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 15KB.
73
- Set to 0 to read the full file in chunks — each chunk up to ~60KB.
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=20_000)
207
+ raw = read_file(file_path, max_size=15_000)
208
208
 
209
209
  if raw.startswith("Error:"):
210
210
  return raw
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aru-code
3
- Version: 0.14.0
3
+ Version: 0.14.1
4
4
  Summary: A Claude Code clone built with Agno agents
5
5
  Author-email: Estevao <estevaofon@gmail.com>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "aru-code"
7
- version = "0.14.0"
7
+ version = "0.14.1"
8
8
  description = "A Claude Code clone built with Agno agents"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -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