aru-code 0.13.1__tar.gz → 0.13.3__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.13.1/aru_code.egg-info → aru_code-0.13.3}/PKG-INFO +1 -1
- aru_code-0.13.3/aru/__init__.py +1 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/cli.py +18 -7
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/context.py +106 -36
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/runner.py +24 -5
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/runtime.py +1 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/tools/codebase.py +3 -3
- {aru_code-0.13.1 → aru_code-0.13.3/aru_code.egg-info}/PKG-INFO +1 -1
- {aru_code-0.13.1 → aru_code-0.13.3}/pyproject.toml +1 -1
- aru_code-0.13.1/aru/__init__.py +0 -1
- {aru_code-0.13.1 → aru_code-0.13.3}/LICENSE +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/README.md +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/agent_factory.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/agents/__init__.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/agents/base.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/agents/executor.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/agents/planner.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/commands.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/completers.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/config.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/display.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/permissions.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/providers.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/session.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/tools/__init__.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/tools/ast_tools.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/tools/gitignore.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/tools/mcp_client.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/tools/ranker.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru/tools/tasklist.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru_code.egg-info/SOURCES.txt +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru_code.egg-info/dependency_links.txt +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru_code.egg-info/entry_points.txt +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru_code.egg-info/requires.txt +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/aru_code.egg-info/top_level.txt +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/setup.cfg +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_agents_base.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_ast_tools.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_cli.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_cli_advanced.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_cli_base.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_cli_completers.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_cli_new.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_cli_run_cli.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_cli_session.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_cli_shell.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_codebase.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_config.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_context.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_executor.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_gitignore.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_main.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_mcp_client.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_permissions.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_planner.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_providers.py +0 -0
- {aru_code-0.13.1 → aru_code-0.13.3}/tests/test_ranker.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.13.3"
|
|
@@ -214,18 +214,29 @@ async def run_cli(skip_permissions: bool = False, resume_id: str | None = None):
|
|
|
214
214
|
_render_input_separator()
|
|
215
215
|
model_tb = session.model_display
|
|
216
216
|
from prompt_toolkit.formatted_text import HTML
|
|
217
|
+
|
|
218
|
+
def _bottom_toolbar():
|
|
219
|
+
mcp_part = ""
|
|
220
|
+
if ctx.mcp_loaded_msg:
|
|
221
|
+
mcp_part = (
|
|
222
|
+
f' <style fg="ansigray">│</style>'
|
|
223
|
+
f' <style fg="ansigray">{ctx.mcp_loaded_msg}</style>'
|
|
224
|
+
)
|
|
225
|
+
return HTML(
|
|
226
|
+
f' <style fg="ansigray">{model_tb}</style>'
|
|
227
|
+
f' <style fg="ansigray">│</style>'
|
|
228
|
+
f' <style fg="ansigray">/help</style>'
|
|
229
|
+
f' <style fg="ansigray">│</style>'
|
|
230
|
+
f' <style fg="ansigray">Esc+Enter newline</style>'
|
|
231
|
+
f'{mcp_part}'
|
|
232
|
+
)
|
|
233
|
+
|
|
217
234
|
user_text = (
|
|
218
235
|
await asyncio.to_thread(
|
|
219
236
|
prompt_session.prompt,
|
|
220
237
|
HTML('<b><ansigreen>❯</ansigreen></b> '),
|
|
221
238
|
multiline=False,
|
|
222
|
-
bottom_toolbar=
|
|
223
|
-
f' <style fg="ansigray">{model_tb}</style>'
|
|
224
|
-
f' <style fg="ansigray">│</style>'
|
|
225
|
-
f' <style fg="ansigray">/help</style>'
|
|
226
|
-
f' <style fg="ansigray">│</style>'
|
|
227
|
-
f' <style fg="ansigray">Esc+Enter newline</style>'
|
|
228
|
-
),
|
|
239
|
+
bottom_toolbar=_bottom_toolbar,
|
|
229
240
|
)
|
|
230
241
|
).strip()
|
|
231
242
|
_render_input_separator()
|
|
@@ -10,8 +10,6 @@ from __future__ import annotations
|
|
|
10
10
|
|
|
11
11
|
# ── Constants ──────────────────────────────────────────────────────
|
|
12
12
|
|
|
13
|
-
# Pruning: protect the most recent N chars of content from eviction
|
|
14
|
-
PRUNE_PROTECT_CHARS = 50_000 # ~14K tokens
|
|
15
13
|
# Pruning: minimum chars that must be freeable to justify a prune pass
|
|
16
14
|
PRUNE_MINIMUM_CHARS = 20_000 # ~5.7K tokens
|
|
17
15
|
# Placeholder that replaces evicted content
|
|
@@ -27,8 +25,10 @@ TRUNCATE_MAX_BYTES = 20 * 1024 # 20 KB
|
|
|
27
25
|
TRUNCATE_KEEP_START = 350 # lines to keep from the start
|
|
28
26
|
TRUNCATE_KEEP_END = 100 # lines to keep from the end
|
|
29
27
|
|
|
30
|
-
# Compaction: trigger when
|
|
28
|
+
# Compaction: trigger when per-run input tokens exceed this fraction of model limit
|
|
31
29
|
COMPACTION_THRESHOLD_RATIO = 0.85
|
|
30
|
+
# Compaction: target post-compaction size as fraction of model context limit
|
|
31
|
+
COMPACTION_TARGET_RATIO = 0.15
|
|
32
32
|
# Default model context limits (input tokens)
|
|
33
33
|
MODEL_CONTEXT_LIMITS: dict[str, int] = {
|
|
34
34
|
# Anthropic
|
|
@@ -83,12 +83,27 @@ Be concise but complete. This summary replaces the full conversation history."""
|
|
|
83
83
|
|
|
84
84
|
# ── Layer 1: Pruning ──────────────────────────────────────────────
|
|
85
85
|
|
|
86
|
-
def
|
|
86
|
+
def _get_prune_protect_chars(model_id: str = "default") -> int:
|
|
87
|
+
"""Scale protection window based on model context size.
|
|
88
|
+
|
|
89
|
+
Larger models get more protection; smaller models prune more aggressively
|
|
90
|
+
to delay compaction. Returns ~10% of the model's context in chars (~3.5 chars/token).
|
|
91
|
+
"""
|
|
92
|
+
limit = MODEL_CONTEXT_LIMITS.get(model_id, MODEL_CONTEXT_LIMITS["default"])
|
|
93
|
+
# ~3.5 chars per token, protect ~10% of context
|
|
94
|
+
protect = int(limit * 0.10 * 3.5)
|
|
95
|
+
# Clamp between 20K (minimum usable) and 80K (diminishing returns)
|
|
96
|
+
return max(20_000, min(protect, 80_000))
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def prune_history(
|
|
100
|
+
history: list[dict[str, str]], model_id: str = "default"
|
|
101
|
+
) -> list[dict[str, str]]:
|
|
87
102
|
"""Replace old messages with a short placeholder to reduce tokens.
|
|
88
103
|
|
|
89
104
|
Walks backward through history, protecting the most recent content
|
|
90
|
-
(
|
|
91
|
-
|
|
105
|
+
(scaled to the model's context size). Older messages beyond that
|
|
106
|
+
budget are pruned:
|
|
92
107
|
- Assistant messages: replaced entirely with placeholder
|
|
93
108
|
- User messages over PRUNE_USER_MSG_THRESHOLD: truncated to first N chars
|
|
94
109
|
|
|
@@ -97,11 +112,13 @@ def prune_history(history: list[dict[str, str]]) -> list[dict[str, str]]:
|
|
|
97
112
|
if len(history) <= 2:
|
|
98
113
|
return list(history)
|
|
99
114
|
|
|
115
|
+
protect_chars = _get_prune_protect_chars(model_id)
|
|
116
|
+
|
|
100
117
|
# Calculate total prunable chars (both roles)
|
|
101
118
|
total_chars = sum(len(msg["content"]) for msg in history)
|
|
102
119
|
|
|
103
120
|
# Not enough to prune
|
|
104
|
-
if total_chars <
|
|
121
|
+
if total_chars < protect_chars + PRUNE_MINIMUM_CHARS:
|
|
105
122
|
return list(history)
|
|
106
123
|
|
|
107
124
|
# Walk backward, protecting recent content
|
|
@@ -112,7 +129,7 @@ def prune_history(history: list[dict[str, str]]) -> list[dict[str, str]]:
|
|
|
112
129
|
msg = result[i]
|
|
113
130
|
msg_len = len(msg["content"])
|
|
114
131
|
|
|
115
|
-
if protected + msg_len <=
|
|
132
|
+
if protected + msg_len <= protect_chars:
|
|
116
133
|
# Still within protection window
|
|
117
134
|
protected += msg_len
|
|
118
135
|
else:
|
|
@@ -121,8 +138,6 @@ def prune_history(history: list[dict[str, str]]) -> list[dict[str, str]]:
|
|
|
121
138
|
if msg["content"] != PRUNED_PLACEHOLDER:
|
|
122
139
|
result[i] = {"role": "assistant", "content": PRUNED_PLACEHOLDER}
|
|
123
140
|
elif msg["role"] == "user" and msg_len > PRUNE_USER_MSG_THRESHOLD:
|
|
124
|
-
# Large user messages (e.g. @file mentions with file contents)
|
|
125
|
-
# are truncated to keep a brief summary of the original request
|
|
126
141
|
truncated = msg["content"][:PRUNE_USER_MSG_KEEP] + \
|
|
127
142
|
f"\n\n[... {msg_len - PRUNE_USER_MSG_KEEP:,} chars pruned to save context ...]"
|
|
128
143
|
result[i] = {"role": "user", "content": truncated}
|
|
@@ -181,21 +196,79 @@ def truncate_output(text: str) -> str:
|
|
|
181
196
|
|
|
182
197
|
# ── Layer 3: Compaction ───────────────────────────────────────────
|
|
183
198
|
|
|
184
|
-
def
|
|
185
|
-
"""
|
|
199
|
+
def estimate_history_tokens(history: list[dict[str, str]]) -> int:
|
|
200
|
+
"""Estimate token count from conversation history chars (~3.5 chars/token)."""
|
|
201
|
+
total_chars = sum(len(msg["content"]) for msg in history)
|
|
202
|
+
return int(total_chars / 3.5)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def should_compact(
|
|
206
|
+
history_or_tokens: int | list[dict[str, str]],
|
|
207
|
+
model_id: str = "default",
|
|
208
|
+
) -> bool:
|
|
209
|
+
"""Check if the conversation should be compacted (reactive, post-run).
|
|
210
|
+
|
|
211
|
+
Accepts either an estimated token count (int) or the history list
|
|
212
|
+
(from which tokens are estimated via char count).
|
|
213
|
+
"""
|
|
214
|
+
if isinstance(history_or_tokens, list):
|
|
215
|
+
tokens = estimate_history_tokens(history_or_tokens)
|
|
216
|
+
else:
|
|
217
|
+
tokens = history_or_tokens
|
|
186
218
|
limit = MODEL_CONTEXT_LIMITS.get(model_id, MODEL_CONTEXT_LIMITS["default"])
|
|
187
219
|
threshold = int(limit * COMPACTION_THRESHOLD_RATIO)
|
|
188
|
-
return
|
|
220
|
+
return tokens >= threshold
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def would_prune(history: list[dict[str, str]], model_id: str = "default") -> bool:
|
|
224
|
+
"""Check if prune_history would discard content from this history.
|
|
225
|
+
|
|
226
|
+
Uses the exact same criteria as prune_history: total chars exceed
|
|
227
|
+
the protection window + minimum prunable threshold.
|
|
228
|
+
"""
|
|
229
|
+
if len(history) <= 2:
|
|
230
|
+
return False
|
|
231
|
+
total_chars = sum(len(msg["content"]) for msg in history)
|
|
232
|
+
protect_chars = _get_prune_protect_chars(model_id)
|
|
233
|
+
return total_chars >= protect_chars + PRUNE_MINIMUM_CHARS
|
|
234
|
+
|
|
189
235
|
|
|
236
|
+
def _split_history(history: list[dict[str, str]], model_id: str = "default") -> tuple[list[dict[str, str]], list[dict[str, str]]]:
|
|
237
|
+
"""Split history into old (to summarize) and recent (to keep intact).
|
|
238
|
+
|
|
239
|
+
Uses the same protection window as pruning.
|
|
240
|
+
"""
|
|
241
|
+
protect_chars = _get_prune_protect_chars(model_id)
|
|
242
|
+
protected = 0
|
|
243
|
+
split_idx = len(history)
|
|
244
|
+
for i in range(len(history) - 1, -1, -1):
|
|
245
|
+
msg_len = len(history[i]["content"])
|
|
246
|
+
if protected + msg_len <= protect_chars:
|
|
247
|
+
protected += msg_len
|
|
248
|
+
split_idx = i
|
|
249
|
+
else:
|
|
250
|
+
break
|
|
251
|
+
return history[:split_idx], history[split_idx:]
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def build_compaction_prompt(
|
|
255
|
+
history: list[dict[str, str]],
|
|
256
|
+
plan_task: str | None = None,
|
|
257
|
+
model_id: str = "default",
|
|
258
|
+
) -> str:
|
|
259
|
+
"""Build the prompt sent to the compaction agent.
|
|
260
|
+
|
|
261
|
+
Only includes OLD messages (outside the protection window) for
|
|
262
|
+
summarization. Recent messages are kept intact by apply_compaction.
|
|
263
|
+
"""
|
|
264
|
+
old_msgs, _ = _split_history(history, model_id)
|
|
190
265
|
|
|
191
|
-
def build_compaction_prompt(history: list[dict[str, str]], plan_task: str | None = None) -> str:
|
|
192
|
-
"""Build the prompt sent to the compaction agent to summarize the conversation."""
|
|
193
266
|
parts = [COMPACTION_TEMPLATE, "\n\n---\n\n## Conversation to summarize:\n"]
|
|
194
267
|
|
|
195
268
|
if plan_task:
|
|
196
269
|
parts.append(f"**Active task:** {plan_task}\n\n")
|
|
197
270
|
|
|
198
|
-
for msg in
|
|
271
|
+
for msg in old_msgs:
|
|
199
272
|
role = msg["role"].upper()
|
|
200
273
|
content = msg["content"]
|
|
201
274
|
# Cap individual messages in the compaction input to avoid blowing up
|
|
@@ -206,26 +279,22 @@ def build_compaction_prompt(history: list[dict[str, str]], plan_task: str | None
|
|
|
206
279
|
return "".join(parts)
|
|
207
280
|
|
|
208
281
|
|
|
209
|
-
|
|
210
|
-
|
|
282
|
+
|
|
283
|
+
def apply_compaction(
|
|
284
|
+
history: list[dict[str, str]], summary: str, model_id: str = "default"
|
|
285
|
+
) -> list[dict[str, str]]:
|
|
286
|
+
"""Replace OLD messages with a summary, keep RECENT messages intact.
|
|
287
|
+
|
|
288
|
+
Uses the same protection window as pruning: recent messages within
|
|
289
|
+
the window are preserved as-is, older messages are replaced by a
|
|
290
|
+
compaction summary. This preserves the natural conversation flow.
|
|
291
|
+
"""
|
|
292
|
+
_, recent = _split_history(history, model_id)
|
|
293
|
+
|
|
211
294
|
compacted = [
|
|
212
295
|
{"role": "user", "content": f"[Conversation compacted]\n\n{summary}"}
|
|
213
296
|
]
|
|
214
|
-
|
|
215
|
-
last_user = None
|
|
216
|
-
last_assistant = None
|
|
217
|
-
for msg in reversed(history):
|
|
218
|
-
if msg["role"] == "user" and last_user is None:
|
|
219
|
-
last_user = msg
|
|
220
|
-
elif msg["role"] == "assistant" and last_assistant is None:
|
|
221
|
-
last_assistant = msg
|
|
222
|
-
if last_user and last_assistant:
|
|
223
|
-
break
|
|
224
|
-
|
|
225
|
-
if last_assistant:
|
|
226
|
-
compacted.append(last_assistant)
|
|
227
|
-
if last_user and last_user != compacted[0]:
|
|
228
|
-
compacted.append(last_user)
|
|
297
|
+
compacted.extend(recent)
|
|
229
298
|
|
|
230
299
|
return compacted
|
|
231
300
|
|
|
@@ -234,6 +303,7 @@ async def compact_conversation(
|
|
|
234
303
|
history: list[dict[str, str]],
|
|
235
304
|
model_ref: str,
|
|
236
305
|
plan_task: str | None = None,
|
|
306
|
+
model_id: str = "default",
|
|
237
307
|
) -> list[dict[str, str]]:
|
|
238
308
|
"""Run the compaction agent to summarize and replace history.
|
|
239
309
|
|
|
@@ -243,7 +313,7 @@ async def compact_conversation(
|
|
|
243
313
|
from aru.runtime import get_ctx
|
|
244
314
|
from aru.providers import create_model
|
|
245
315
|
|
|
246
|
-
prompt = build_compaction_prompt(history, plan_task)
|
|
316
|
+
prompt = build_compaction_prompt(history, plan_task, model_id=model_id)
|
|
247
317
|
|
|
248
318
|
try:
|
|
249
319
|
from agno.agent import Agent
|
|
@@ -263,12 +333,12 @@ async def compact_conversation(
|
|
|
263
333
|
# Fallback: simple mechanical summary
|
|
264
334
|
summary = _fallback_summary(history, plan_task)
|
|
265
335
|
|
|
266
|
-
return apply_compaction(history, summary)
|
|
336
|
+
return apply_compaction(history, summary, model_id=model_id)
|
|
267
337
|
|
|
268
338
|
except Exception:
|
|
269
339
|
# Fallback if agent fails
|
|
270
340
|
summary = _fallback_summary(history, plan_task)
|
|
271
|
-
return apply_compaction(history, summary)
|
|
341
|
+
return apply_compaction(history, summary, model_id=model_id)
|
|
272
342
|
|
|
273
343
|
|
|
274
344
|
def _fallback_summary(history: list[dict[str, str]], plan_task: str | None = None) -> str:
|
|
@@ -115,11 +115,25 @@ async def run_agent_capture(agent, message: str, session=None, lightweight: bool
|
|
|
115
115
|
run_message = message
|
|
116
116
|
|
|
117
117
|
# Build conversation history as real messages for the LLM
|
|
118
|
-
|
|
118
|
+
# Compact BEFORE pruning: if the history is large enough that pruning
|
|
119
|
+
# would discard content, compact first to preserve context via summary
|
|
120
|
+
# instead of losing it to placeholders.
|
|
121
|
+
from aru.context import prune_history, should_compact, compact_conversation, would_prune
|
|
122
|
+
if session and session.history and not lightweight:
|
|
123
|
+
if would_prune(session.history, model_id=session.model_id):
|
|
124
|
+
try:
|
|
125
|
+
session.history = await compact_conversation(
|
|
126
|
+
session.history, session.model_ref, session.plan_task,
|
|
127
|
+
model_id=session.model_id,
|
|
128
|
+
)
|
|
129
|
+
console.print("[dim]Context compacted to save tokens.[/dim]")
|
|
130
|
+
except Exception:
|
|
131
|
+
pass
|
|
132
|
+
|
|
119
133
|
history_messages: list[Message] = []
|
|
120
134
|
if session and session.history and not lightweight:
|
|
121
135
|
prior_history = session.history[:-1]
|
|
122
|
-
pruned = prune_history(prior_history)
|
|
136
|
+
pruned = prune_history(prior_history, model_id=session.model_id)
|
|
123
137
|
for msg in pruned:
|
|
124
138
|
history_messages.append(Message(role=msg["role"], content=msg["content"], from_history=True))
|
|
125
139
|
|
|
@@ -228,11 +242,16 @@ async def run_agent_capture(agent, message: str, session=None, lightweight: bool
|
|
|
228
242
|
if run_output and session and hasattr(run_output, "metrics"):
|
|
229
243
|
session.track_tokens(run_output.metrics)
|
|
230
244
|
|
|
231
|
-
|
|
232
|
-
|
|
245
|
+
# Reactive compaction: use per-run input_tokens (sum of all API
|
|
246
|
+
# calls within this arun) as a conservative proxy for context pressure.
|
|
247
|
+
# session.history doesn't include tool results, so char-based estimates
|
|
248
|
+
# would miss the bulk of the context sent to the model.
|
|
249
|
+
run_input_tokens = getattr(run_output.metrics, "input_tokens", 0) or 0
|
|
250
|
+
if should_compact(run_input_tokens, session.model_id):
|
|
233
251
|
try:
|
|
234
252
|
session.history = await compact_conversation(
|
|
235
|
-
session.history, session.model_ref, session.plan_task
|
|
253
|
+
session.history, session.model_ref, session.plan_task,
|
|
254
|
+
model_id=session.model_id,
|
|
236
255
|
)
|
|
237
256
|
console.print("[dim]Context compacted to save tokens.[/dim]")
|
|
238
257
|
except Exception:
|
|
@@ -1232,7 +1232,7 @@ async def load_mcp_tools(eager: bool = False):
|
|
|
1232
1232
|
if eager:
|
|
1233
1233
|
# Legacy: each MCP tool = one Agno Function (expensive)
|
|
1234
1234
|
mcp_tools = manager.get_eager_tools()
|
|
1235
|
-
get_ctx().
|
|
1235
|
+
get_ctx().mcp_loaded_msg = f"Loaded {tool_count} tools from MCP servers (eager mode)."
|
|
1236
1236
|
for t in mcp_tools:
|
|
1237
1237
|
ALL_TOOLS.append(t)
|
|
1238
1238
|
EXECUTOR_TOOLS.append(t)
|
|
@@ -1245,10 +1245,10 @@ async def load_mcp_tools(eager: bool = False):
|
|
|
1245
1245
|
GENERAL_TOOLS.append(gateway)
|
|
1246
1246
|
# Store catalog text for injection into system prompt
|
|
1247
1247
|
get_ctx().mcp_catalog_text = manager.get_catalog_text()
|
|
1248
|
-
get_ctx().
|
|
1248
|
+
get_ctx().mcp_loaded_msg = f"Loaded {tool_count} tools from MCP servers."
|
|
1249
1249
|
|
|
1250
1250
|
except Exception as e:
|
|
1251
|
-
get_ctx().
|
|
1251
|
+
get_ctx().mcp_loaded_msg = f"Failed to load MCP tools: {e}"
|
|
1252
1252
|
|
|
1253
1253
|
|
|
1254
1254
|
def _build_mcp_gateway(manager):
|
aru_code-0.13.1/aru/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.13.1"
|
|
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
|