gemcode 0.3.67__tar.gz → 0.3.69__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.
- {gemcode-0.3.67/src/gemcode.egg-info → gemcode-0.3.69}/PKG-INFO +1 -1
- {gemcode-0.3.67 → gemcode-0.3.69}/pyproject.toml +1 -1
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/callbacks.py +54 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/config.py +10 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/dynamic_policy.py +50 -24
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/invoke.py +26 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/repl_slash.py +14 -0
- {gemcode-0.3.67 → gemcode-0.3.69/src/gemcode.egg-info}/PKG-INFO +1 -1
- {gemcode-0.3.67 → gemcode-0.3.69}/LICENSE +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/MANIFEST.in +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/README.md +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/setup.cfg +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/__init__.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/__main__.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/agent.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/audit.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/autocompact.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/capability_routing.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/cli.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/compaction.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/computer_use/__init__.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/computer_use/browser_computer.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/context_budget.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/context_warning.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/credentials.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/hitl_session.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/hooks.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/intent_classifier.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/interactions.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/kairos_daemon.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/limits.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/live_audio_engine.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/logging_config.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/mcp_loader.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/memory/__init__.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/memory/embedding_memory_service.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/memory/file_memory_service.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/modality_tools.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/model_errors.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/model_routing.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/openapi_loader.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/paths.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/permissions.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/plugins/__init__.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/plugins/terminal_hooks_plugin.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/plugins/tool_recovery_plugin.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/pricing.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/prompt_suggestions.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/query/__init__.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/query/config.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/query/deps.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/query/engine.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/query/stop_hooks.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/query/token_budget.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/query/transitions.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/refine.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/repl_commands.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/review_agent.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/session_runtime.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/session_store.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/slash_commands.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/thinking.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tool_prompt_manifest.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tool_registry.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tool_result_store.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools/__init__.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools/bash.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools/browser.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools/edit.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools/filesystem.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools/notebook.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools/notes.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools/repo_map.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools/search.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools/shell.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools/shell_gate.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools/subtask.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools/tasks.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools/think.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools/todo.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools/web.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools/web_search.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tools_inspector.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/trust.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tui/input_handler.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tui/scrollback.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tui/spinner.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tui/welcome_banner.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/tui/welcome_rich.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/version.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/vertex.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/web/__init__.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/web/claude_sse_adapter.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/web/terminal_repl.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode/workspace_hints.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode.egg-info/SOURCES.txt +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode.egg-info/dependency_links.txt +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode.egg-info/entry_points.txt +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode.egg-info/requires.txt +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/src/gemcode.egg-info/top_level.txt +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_agent_instruction.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_autocompact.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_capability_routing.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_claude_web_adapter_sse.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_cli_init.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_computer_use_permissions.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_context_budget.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_context_warning.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_credentials.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_interactive_permission_ask.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_kairos_scheduler.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_modality_tools.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_model_error_retry.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_model_errors.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_model_routing.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_paths.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_permissions.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_prompt_suggestions.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_repl_commands.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_repl_slash.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_slash_commands.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_thinking_config.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_token_budget.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_tool_context_circulation.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_tools.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_tools_inspector.py +0 -0
- {gemcode-0.3.67 → gemcode-0.3.69}/tests/test_workspace_hints.py +0 -0
|
@@ -43,6 +43,8 @@ _CTX_WARN_LEVEL_NOTIFIED = "gemcode:ctx_warn_level_notified"
|
|
|
43
43
|
_LAST_PROMPT_TOKENS = "gemcode:last_prompt_tokens"
|
|
44
44
|
_LAST_CONTEXT_PCT = "gemcode:last_context_percent_left"
|
|
45
45
|
_LAST_CONTEXT_LEVEL = "gemcode:last_context_alert_level"
|
|
46
|
+
_RISK_FILES_TOUCHED = "gemcode:risk_files_touched"
|
|
47
|
+
_RISK_TOOL_CALLS = "gemcode:risk_tool_calls"
|
|
46
48
|
|
|
47
49
|
def _truthy_env(name: str, *, default: bool = False) -> bool:
|
|
48
50
|
v = os.environ.get(name)
|
|
@@ -141,6 +143,36 @@ def make_before_tool_callback(cfg: GemCodeConfig):
|
|
|
141
143
|
record = {"tool": name, "args": _redact_args(name, args)}
|
|
142
144
|
append_audit(cfg.project_root, record)
|
|
143
145
|
|
|
146
|
+
# Dynamic risk signals from actual repo interaction.
|
|
147
|
+
try:
|
|
148
|
+
if tool_context is not None:
|
|
149
|
+
st = tool_context.state
|
|
150
|
+
st[_RISK_TOOL_CALLS] = int(st.get(_RISK_TOOL_CALLS, 0) or 0) + 1
|
|
151
|
+
if name == "read_file":
|
|
152
|
+
p = (args or {}).get("path")
|
|
153
|
+
if isinstance(p, str) and p.strip():
|
|
154
|
+
touched: set[str] = set(st.get(_RISK_FILES_TOUCHED, []) or [])
|
|
155
|
+
touched.add(p.strip())
|
|
156
|
+
# Store as list for JSON-serializable session state.
|
|
157
|
+
st[_RISK_FILES_TOUCHED] = list(sorted(touched))[:200]
|
|
158
|
+
# More files touched => higher complexity.
|
|
159
|
+
n = len(touched)
|
|
160
|
+
cur = float(getattr(cfg, "_risk_score", 0.0) or 0.0)
|
|
161
|
+
if n >= 10:
|
|
162
|
+
cur = min(1.0, cur + 0.08)
|
|
163
|
+
elif n >= 5:
|
|
164
|
+
cur = min(1.0, cur + 0.04)
|
|
165
|
+
object.__setattr__(cfg, "_risk_score", cur)
|
|
166
|
+
# Writes / shell are inherently higher risk; allow more evidence.
|
|
167
|
+
if name in MUTATING_TOOLS:
|
|
168
|
+
cur = float(getattr(cfg, "_risk_score", 0.0) or 0.0)
|
|
169
|
+
object.__setattr__(cfg, "_risk_score", min(1.0, cur + 0.12))
|
|
170
|
+
if name in SHELL_TOOLS:
|
|
171
|
+
cur = float(getattr(cfg, "_risk_score", 0.0) or 0.0)
|
|
172
|
+
object.__setattr__(cfg, "_risk_score", min(1.0, cur + 0.08))
|
|
173
|
+
except Exception:
|
|
174
|
+
pass
|
|
175
|
+
|
|
144
176
|
# ── Shell hooks: pre_tool_use ─────────────────────────────────────────
|
|
145
177
|
# If the project has a .gemcode/hooks/pre_tool_use.sh, run it now.
|
|
146
178
|
# Non-zero exit or {"decision":"deny"} stdout will block the tool call.
|
|
@@ -384,6 +416,28 @@ def make_after_tool_callback(cfg: GemCodeConfig):
|
|
|
384
416
|
st[_STATE_FAILURE_KEY] = 0
|
|
385
417
|
else:
|
|
386
418
|
st[_STATE_FAILURE_KEY] = 0
|
|
419
|
+
|
|
420
|
+
# Risk feedback: if tools are failing or commands return non-zero, treat the
|
|
421
|
+
# task as higher-risk and allow more evidence in subsequent tool outputs.
|
|
422
|
+
try:
|
|
423
|
+
cur = float(getattr(cfg, "_risk_score", 0.0) or 0.0)
|
|
424
|
+
bump = 0.0
|
|
425
|
+
if err:
|
|
426
|
+
bump += 0.15
|
|
427
|
+
if isinstance(tool_response, dict) and isinstance(tool_response.get("exit_code"), int):
|
|
428
|
+
if int(tool_response["exit_code"]) != 0:
|
|
429
|
+
bump += 0.10
|
|
430
|
+
# Test/build failures should boost evidence allowance more.
|
|
431
|
+
if name in ("bash", "run_command"):
|
|
432
|
+
bump += 0.05
|
|
433
|
+
# decay slowly when things are healthy
|
|
434
|
+
if bump == 0.0:
|
|
435
|
+
cur = max(0.0, cur * 0.90)
|
|
436
|
+
else:
|
|
437
|
+
cur = min(1.0, cur + bump)
|
|
438
|
+
object.__setattr__(cfg, "_risk_score", cur)
|
|
439
|
+
except Exception:
|
|
440
|
+
pass
|
|
387
441
|
# ── Shell hooks: post_tool_use ────────────────────────────────────────
|
|
388
442
|
try:
|
|
389
443
|
from gemcode.hooks import run_post_tool_use_hook
|
|
@@ -143,6 +143,16 @@ class GemCodeConfig:
|
|
|
143
143
|
dynamic_token_policy: bool = field(
|
|
144
144
|
default_factory=lambda: _truthy_env("GEMCODE_DYNAMIC_TOKEN_POLICY", default=True)
|
|
145
145
|
)
|
|
146
|
+
|
|
147
|
+
# Dynamic risk policy: boosts caps when the current task appears risky/complex.
|
|
148
|
+
dynamic_risk_policy: bool = field(
|
|
149
|
+
default_factory=lambda: _truthy_env("GEMCODE_DYNAMIC_RISK_POLICY", default=True)
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
# How much the risk score can expand caps (0.0-1.5 reasonable).
|
|
153
|
+
dynamic_risk_boost: float = field(
|
|
154
|
+
default_factory=lambda: float(os.environ.get("GEMCODE_DYNAMIC_RISK_BOOST", "0.6"))
|
|
155
|
+
)
|
|
146
156
|
# Trim oldest text in llm_request.contents when over budget (see context_budget.py).
|
|
147
157
|
context_shrink_enabled: bool = field(
|
|
148
158
|
default_factory=lambda: _truthy_env("GEMCODE_CONTEXT_SHRINK", default=True)
|
|
@@ -32,6 +32,20 @@ def _pct_left(cfg) -> int | None:
|
|
|
32
32
|
return None
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
def _risk(cfg) -> float:
|
|
36
|
+
try:
|
|
37
|
+
v = getattr(cfg, "_risk_score", None)
|
|
38
|
+
if isinstance(v, (int, float)):
|
|
39
|
+
return float(v)
|
|
40
|
+
except Exception:
|
|
41
|
+
return 0.0
|
|
42
|
+
return 0.0
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _clamp(x: float, lo: float, hi: float) -> float:
|
|
46
|
+
return lo if x < lo else hi if x > hi else x
|
|
47
|
+
|
|
48
|
+
|
|
35
49
|
@dataclass(frozen=True)
|
|
36
50
|
class DynamicCaps:
|
|
37
51
|
tool_inline_chars: int
|
|
@@ -52,6 +66,8 @@ def get_dynamic_caps(cfg) -> DynamicCaps:
|
|
|
52
66
|
- Healthy (>=45% left): generous caps (better evidence, less re-asking).
|
|
53
67
|
- Warning (20-44%): moderate caps.
|
|
54
68
|
- Tight (<20%): strict caps + prefer offload.
|
|
69
|
+
|
|
70
|
+
Then apply a risk-based boost (if enabled) so complex tasks stay evidence-rich.
|
|
55
71
|
"""
|
|
56
72
|
# cfg can be None in some tool contexts; treat as enabled with defaults.
|
|
57
73
|
enabled = _truthy(getattr(cfg, "dynamic_token_policy", True) if cfg is not None else True, default=True)
|
|
@@ -76,42 +92,52 @@ def get_dynamic_caps(cfg) -> DynamicCaps:
|
|
|
76
92
|
base_tool = int(getattr(cfg, "tool_result_max_chars", 12000) or 12000) if cfg is not None else 12000
|
|
77
93
|
base_tool = max(1000, base_tool)
|
|
78
94
|
|
|
95
|
+
# Risk boost: scale caps upward for risky tasks, but keep bounded.
|
|
96
|
+
risk_enabled = _truthy(getattr(cfg, "dynamic_risk_policy", True) if cfg is not None else True, default=True)
|
|
97
|
+
risk_boost = float(getattr(cfg, "dynamic_risk_boost", 0.6) if cfg is not None else 0.6)
|
|
98
|
+
risk_score = _risk(cfg) if (cfg is not None and risk_enabled) else 0.0
|
|
99
|
+
risk_score = _clamp(risk_score, 0.0, 1.0)
|
|
100
|
+
boost = 1.0 + (_clamp(risk_boost, 0.0, 1.5) * risk_score)
|
|
101
|
+
|
|
102
|
+
def _scale(n: int, *, cap: int) -> int:
|
|
103
|
+
return min(cap, max(1000, int(n * boost)))
|
|
104
|
+
|
|
79
105
|
if pct >= 45:
|
|
80
106
|
mult = 1.4
|
|
81
107
|
return DynamicCaps(
|
|
82
|
-
tool_inline_chars=min(24_000, int(base_tool * mult)),
|
|
83
|
-
read_file_max_bytes=140_000,
|
|
84
|
-
web_fetch_max_chars=30_000,
|
|
85
|
-
bash_stdout_chars=30_000,
|
|
86
|
-
bash_stderr_chars=15_000,
|
|
87
|
-
run_stdout_chars=30_000,
|
|
88
|
-
run_stderr_chars=30_000,
|
|
89
|
-
grep_max_matches=60,
|
|
108
|
+
tool_inline_chars=_scale(min(24_000, int(base_tool * mult)), cap=30_000),
|
|
109
|
+
read_file_max_bytes=min(200_000, int(140_000 * boost)),
|
|
110
|
+
web_fetch_max_chars=min(60_000, int(30_000 * boost)),
|
|
111
|
+
bash_stdout_chars=min(80_000, int(30_000 * boost)),
|
|
112
|
+
bash_stderr_chars=min(40_000, int(15_000 * boost)),
|
|
113
|
+
run_stdout_chars=min(80_000, int(30_000 * boost)),
|
|
114
|
+
run_stderr_chars=min(80_000, int(30_000 * boost)),
|
|
115
|
+
grep_max_matches=min(200, int(60 * boost)),
|
|
90
116
|
)
|
|
91
117
|
|
|
92
118
|
if pct >= 20:
|
|
93
119
|
mult = 1.0
|
|
94
120
|
return DynamicCaps(
|
|
95
|
-
tool_inline_chars=min(18_000, int(base_tool * mult)),
|
|
96
|
-
read_file_max_bytes=80_000,
|
|
97
|
-
web_fetch_max_chars=20_000,
|
|
98
|
-
bash_stdout_chars=20_000,
|
|
99
|
-
bash_stderr_chars=10_000,
|
|
100
|
-
run_stdout_chars=20_000,
|
|
101
|
-
run_stderr_chars=20_000,
|
|
102
|
-
grep_max_matches=40,
|
|
121
|
+
tool_inline_chars=_scale(min(18_000, int(base_tool * mult)), cap=24_000),
|
|
122
|
+
read_file_max_bytes=min(160_000, int(80_000 * boost)),
|
|
123
|
+
web_fetch_max_chars=min(40_000, int(20_000 * boost)),
|
|
124
|
+
bash_stdout_chars=min(50_000, int(20_000 * boost)),
|
|
125
|
+
bash_stderr_chars=min(30_000, int(10_000 * boost)),
|
|
126
|
+
run_stdout_chars=min(50_000, int(20_000 * boost)),
|
|
127
|
+
run_stderr_chars=min(50_000, int(20_000 * boost)),
|
|
128
|
+
grep_max_matches=min(120, int(40 * boost)),
|
|
103
129
|
)
|
|
104
130
|
|
|
105
131
|
# Tight
|
|
106
132
|
mult = 0.6
|
|
107
133
|
return DynamicCaps(
|
|
108
|
-
tool_inline_chars=max(2000, int(base_tool * mult)),
|
|
109
|
-
read_file_max_bytes=35_000,
|
|
110
|
-
web_fetch_max_chars=10_000,
|
|
111
|
-
bash_stdout_chars=10_000,
|
|
112
|
-
bash_stderr_chars=8_000,
|
|
113
|
-
run_stdout_chars=10_000,
|
|
114
|
-
run_stderr_chars=10_000,
|
|
115
|
-
grep_max_matches=20,
|
|
134
|
+
tool_inline_chars=max(2000, min(12_000, int(base_tool * mult * boost))),
|
|
135
|
+
read_file_max_bytes=min(90_000, int(35_000 * boost)),
|
|
136
|
+
web_fetch_max_chars=min(20_000, int(10_000 * boost)),
|
|
137
|
+
bash_stdout_chars=min(25_000, int(10_000 * boost)),
|
|
138
|
+
bash_stderr_chars=min(20_000, int(8_000 * boost)),
|
|
139
|
+
run_stdout_chars=min(25_000, int(10_000 * boost)),
|
|
140
|
+
run_stderr_chars=min(25_000, int(10_000 * boost)),
|
|
141
|
+
grep_max_matches=min(80, int(20 * boost)),
|
|
116
142
|
)
|
|
117
143
|
|
|
@@ -68,6 +68,32 @@ async def run_turn(
|
|
|
68
68
|
cfg: "GemCodeConfig | None" = None,
|
|
69
69
|
) -> list:
|
|
70
70
|
"""Execute one user message; collect all Events (caller aggregates text)."""
|
|
71
|
+
# Dynamic risk score: updated each user message; later refined by tool outcomes.
|
|
72
|
+
# This is intentionally heuristic but configurable via env knobs.
|
|
73
|
+
if cfg is not None:
|
|
74
|
+
try:
|
|
75
|
+
import re
|
|
76
|
+
p = (prompt or "")[:20_000]
|
|
77
|
+
risk = 0.0
|
|
78
|
+
# Complexity signals
|
|
79
|
+
if len(p) > 600:
|
|
80
|
+
risk += 0.15
|
|
81
|
+
if len(p) > 2000:
|
|
82
|
+
risk += 0.15
|
|
83
|
+
if re.search(r"\\b(refactor|migrate|rewrite|optimi[sz]e|architecture)\\b", p, re.I):
|
|
84
|
+
risk += 0.2
|
|
85
|
+
if re.search(r"\\b(bug|fix|regression|error|traceback|failing)\\b", p, re.I):
|
|
86
|
+
risk += 0.2
|
|
87
|
+
if re.search(r"\\b(test|pytest|ci|build|deploy|release)\\b", p, re.I):
|
|
88
|
+
risk += 0.1
|
|
89
|
+
# Multi-file hints
|
|
90
|
+
if p.count(\"/\") >= 6 or p.count(\".py\") + p.count(\".ts\") + p.count(\".tsx\") >= 3:
|
|
91
|
+
risk += 0.1
|
|
92
|
+
# Clamp 0..1
|
|
93
|
+
risk = max(0.0, min(1.0, float(risk)))
|
|
94
|
+
object.__setattr__(cfg, \"_risk_score\", risk)
|
|
95
|
+
except Exception:
|
|
96
|
+
pass
|
|
71
97
|
run_config = (
|
|
72
98
|
RunConfig(max_llm_calls=max_llm_calls) if max_llm_calls is not None else None
|
|
73
99
|
)
|
|
@@ -391,6 +391,20 @@ async def process_repl_slash(
|
|
|
391
391
|
out(f" thinking_budget: {cfg.thinking_budget if cfg.thinking_budget is not None else '(auto)'}")
|
|
392
392
|
out(f" show_full_thinking: {cfg.show_full_thinking}")
|
|
393
393
|
out()
|
|
394
|
+
# Dynamic policy telemetry
|
|
395
|
+
try:
|
|
396
|
+
risk = float(getattr(cfg, "_risk_score", 0.0) or 0.0)
|
|
397
|
+
pct = getattr(cfg, "_context_percent_left", None)
|
|
398
|
+
out(" Dynamic policy:")
|
|
399
|
+
out(f" dynamic_token_policy: {getattr(cfg, 'dynamic_token_policy', True)}")
|
|
400
|
+
out(f" dynamic_risk_policy: {getattr(cfg, 'dynamic_risk_policy', True)}")
|
|
401
|
+
out(f" dynamic_risk_boost: {getattr(cfg, 'dynamic_risk_boost', 0.6)}")
|
|
402
|
+
out(f" risk_score: {risk:.2f}")
|
|
403
|
+
if isinstance(pct, int):
|
|
404
|
+
out(f" context_percent_left: {pct}%")
|
|
405
|
+
out()
|
|
406
|
+
except Exception:
|
|
407
|
+
pass
|
|
394
408
|
out(" Autocompact:")
|
|
395
409
|
out(f" GEMCODE_AUTOCOMPACT: {os.environ.get('GEMCODE_AUTOCOMPACT', '1')}")
|
|
396
410
|
out(f" GEMCODE_AUTOCOMPACT_BUFFER_CHARS: {os.environ.get('GEMCODE_AUTOCOMPACT_BUFFER_CHARS', '60000')}")
|
|
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
|
|
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
|
|
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
|