gemcode 0.3.69__tar.gz → 0.3.70__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.69/src/gemcode.egg-info → gemcode-0.3.70}/PKG-INFO +1 -1
- {gemcode-0.3.69 → gemcode-0.3.70}/pyproject.toml +1 -1
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/callbacks.py +34 -0
- gemcode-0.3.70/src/gemcode/policy_profile.py +135 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/repl_slash.py +7 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/session_runtime.py +10 -0
- {gemcode-0.3.69 → gemcode-0.3.70/src/gemcode.egg-info}/PKG-INFO +1 -1
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode.egg-info/SOURCES.txt +1 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/LICENSE +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/MANIFEST.in +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/README.md +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/setup.cfg +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/__init__.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/__main__.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/agent.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/audit.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/autocompact.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/capability_routing.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/cli.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/compaction.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/computer_use/__init__.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/computer_use/browser_computer.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/config.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/context_budget.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/context_warning.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/credentials.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/dynamic_policy.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/hitl_session.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/hooks.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/intent_classifier.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/interactions.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/invoke.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/kairos_daemon.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/limits.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/live_audio_engine.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/logging_config.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/mcp_loader.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/memory/__init__.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/memory/embedding_memory_service.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/memory/file_memory_service.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/modality_tools.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/model_errors.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/model_routing.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/openapi_loader.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/paths.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/permissions.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/plugins/__init__.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/plugins/terminal_hooks_plugin.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/plugins/tool_recovery_plugin.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/pricing.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/prompt_suggestions.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/query/__init__.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/query/config.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/query/deps.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/query/engine.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/query/stop_hooks.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/query/token_budget.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/query/transitions.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/refine.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/repl_commands.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/review_agent.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/session_store.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/slash_commands.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/thinking.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tool_prompt_manifest.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tool_registry.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tool_result_store.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools/__init__.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools/bash.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools/browser.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools/edit.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools/filesystem.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools/notebook.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools/notes.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools/repo_map.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools/search.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools/shell.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools/shell_gate.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools/subtask.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools/tasks.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools/think.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools/todo.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools/web.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools/web_search.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tools_inspector.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/trust.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tui/input_handler.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tui/scrollback.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tui/spinner.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tui/welcome_banner.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/tui/welcome_rich.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/version.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/vertex.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/web/__init__.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/web/claude_sse_adapter.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/web/terminal_repl.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode/workspace_hints.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode.egg-info/dependency_links.txt +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode.egg-info/entry_points.txt +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode.egg-info/requires.txt +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/src/gemcode.egg-info/top_level.txt +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_agent_instruction.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_autocompact.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_capability_routing.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_claude_web_adapter_sse.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_cli_init.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_computer_use_permissions.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_context_budget.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_context_warning.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_credentials.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_interactive_permission_ask.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_kairos_scheduler.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_modality_tools.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_model_error_retry.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_model_errors.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_model_routing.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_paths.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_permissions.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_prompt_suggestions.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_repl_commands.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_repl_slash.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_slash_commands.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_thinking_config.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_token_budget.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_tool_context_circulation.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_tools.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_tools_inspector.py +0 -0
- {gemcode-0.3.69 → gemcode-0.3.70}/tests/test_workspace_hints.py +0 -0
|
@@ -45,6 +45,9 @@ _LAST_CONTEXT_PCT = "gemcode:last_context_percent_left"
|
|
|
45
45
|
_LAST_CONTEXT_LEVEL = "gemcode:last_context_alert_level"
|
|
46
46
|
_RISK_FILES_TOUCHED = "gemcode:risk_files_touched"
|
|
47
47
|
_RISK_TOOL_CALLS = "gemcode:risk_tool_calls"
|
|
48
|
+
_RISK_HAD_SHELL = "gemcode:risk_had_shell"
|
|
49
|
+
_RISK_HAD_WRITE = "gemcode:risk_had_write"
|
|
50
|
+
_RISK_HAD_FAILURE = "gemcode:risk_had_failure"
|
|
48
51
|
|
|
49
52
|
def _truthy_env(name: str, *, default: bool = False) -> bool:
|
|
50
53
|
v = os.environ.get(name)
|
|
@@ -165,9 +168,11 @@ def make_before_tool_callback(cfg: GemCodeConfig):
|
|
|
165
168
|
object.__setattr__(cfg, "_risk_score", cur)
|
|
166
169
|
# Writes / shell are inherently higher risk; allow more evidence.
|
|
167
170
|
if name in MUTATING_TOOLS:
|
|
171
|
+
st[_RISK_HAD_WRITE] = True
|
|
168
172
|
cur = float(getattr(cfg, "_risk_score", 0.0) or 0.0)
|
|
169
173
|
object.__setattr__(cfg, "_risk_score", min(1.0, cur + 0.12))
|
|
170
174
|
if name in SHELL_TOOLS:
|
|
175
|
+
st[_RISK_HAD_SHELL] = True
|
|
171
176
|
cur = float(getattr(cfg, "_risk_score", 0.0) or 0.0)
|
|
172
177
|
object.__setattr__(cfg, "_risk_score", min(1.0, cur + 0.08))
|
|
173
178
|
except Exception:
|
|
@@ -423,9 +428,17 @@ def make_after_tool_callback(cfg: GemCodeConfig):
|
|
|
423
428
|
cur = float(getattr(cfg, "_risk_score", 0.0) or 0.0)
|
|
424
429
|
bump = 0.0
|
|
425
430
|
if err:
|
|
431
|
+
try:
|
|
432
|
+
st[_RISK_HAD_FAILURE] = True
|
|
433
|
+
except Exception:
|
|
434
|
+
pass
|
|
426
435
|
bump += 0.15
|
|
427
436
|
if isinstance(tool_response, dict) and isinstance(tool_response.get("exit_code"), int):
|
|
428
437
|
if int(tool_response["exit_code"]) != 0:
|
|
438
|
+
try:
|
|
439
|
+
st[_RISK_HAD_FAILURE] = True
|
|
440
|
+
except Exception:
|
|
441
|
+
pass
|
|
429
442
|
bump += 0.10
|
|
430
443
|
# Test/build failures should boost evidence allowance more.
|
|
431
444
|
if name in ("bash", "run_command"):
|
|
@@ -438,6 +451,27 @@ def make_after_tool_callback(cfg: GemCodeConfig):
|
|
|
438
451
|
object.__setattr__(cfg, "_risk_score", cur)
|
|
439
452
|
except Exception:
|
|
440
453
|
pass
|
|
454
|
+
|
|
455
|
+
# Persist repo calibration profile (best-effort).
|
|
456
|
+
try:
|
|
457
|
+
files = st.get(_RISK_FILES_TOUCHED, []) or []
|
|
458
|
+
files_n = len(files) if isinstance(files, list) else 0
|
|
459
|
+
tool_calls = int(st.get(_RISK_TOOL_CALLS, 0) or 0)
|
|
460
|
+
had_shell = bool(st.get(_RISK_HAD_SHELL, False))
|
|
461
|
+
had_write = bool(st.get(_RISK_HAD_WRITE, False))
|
|
462
|
+
had_failure = bool(st.get(_RISK_HAD_FAILURE, False))
|
|
463
|
+
from gemcode.policy_profile import update_profile
|
|
464
|
+
prof = update_profile(
|
|
465
|
+
cfg.project_root,
|
|
466
|
+
files_touched=files_n,
|
|
467
|
+
tool_calls=tool_calls,
|
|
468
|
+
had_shell=had_shell,
|
|
469
|
+
had_write=had_write,
|
|
470
|
+
had_failure=had_failure,
|
|
471
|
+
)
|
|
472
|
+
object.__setattr__(cfg, "_policy_profile", prof.to_dict())
|
|
473
|
+
except Exception:
|
|
474
|
+
pass
|
|
441
475
|
# ── Shell hooks: post_tool_use ────────────────────────────────────────
|
|
442
476
|
try:
|
|
443
477
|
from gemcode.hooks import run_post_tool_use_hook
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Persistent per-repo policy profile.
|
|
3
|
+
|
|
4
|
+
Goal: make dynamic budgets self-tuning per repository without requiring manual
|
|
5
|
+
configuration. This stores lightweight rolling stats under `.gemcode/policy.json`.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import time
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _path(root: Path) -> Path:
|
|
18
|
+
d = root / ".gemcode"
|
|
19
|
+
d.mkdir(parents=True, exist_ok=True)
|
|
20
|
+
return d / "policy.json"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _clamp(x: float, lo: float, hi: float) -> float:
|
|
24
|
+
return lo if x < lo else hi if x > hi else x
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _ema(prev: float, x: float, *, alpha: float) -> float:
|
|
28
|
+
return (alpha * x) + ((1.0 - alpha) * prev)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(frozen=True)
|
|
32
|
+
class PolicyProfile:
|
|
33
|
+
# Rolling averages in [0,1] where possible.
|
|
34
|
+
failure_rate_ema: float = 0.0
|
|
35
|
+
shell_rate_ema: float = 0.0
|
|
36
|
+
write_rate_ema: float = 0.0
|
|
37
|
+
files_touched_ema: float = 0.0 # scaled 0..1 (e.g. 0.5 ~ 10 files)
|
|
38
|
+
updated_at: int = 0
|
|
39
|
+
|
|
40
|
+
def to_dict(self) -> dict[str, Any]:
|
|
41
|
+
return {
|
|
42
|
+
"failure_rate_ema": self.failure_rate_ema,
|
|
43
|
+
"shell_rate_ema": self.shell_rate_ema,
|
|
44
|
+
"write_rate_ema": self.write_rate_ema,
|
|
45
|
+
"files_touched_ema": self.files_touched_ema,
|
|
46
|
+
"updated_at": self.updated_at,
|
|
47
|
+
"version": 1,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def from_dict(d: dict[str, Any]) -> "PolicyProfile":
|
|
52
|
+
try:
|
|
53
|
+
return PolicyProfile(
|
|
54
|
+
failure_rate_ema=float(d.get("failure_rate_ema", 0.0) or 0.0),
|
|
55
|
+
shell_rate_ema=float(d.get("shell_rate_ema", 0.0) or 0.0),
|
|
56
|
+
write_rate_ema=float(d.get("write_rate_ema", 0.0) or 0.0),
|
|
57
|
+
files_touched_ema=float(d.get("files_touched_ema", 0.0) or 0.0),
|
|
58
|
+
updated_at=int(d.get("updated_at", 0) or 0),
|
|
59
|
+
)
|
|
60
|
+
except Exception:
|
|
61
|
+
return PolicyProfile()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def load_profile(project_root: Path) -> PolicyProfile:
|
|
65
|
+
p = _path(project_root)
|
|
66
|
+
if not p.exists():
|
|
67
|
+
return PolicyProfile()
|
|
68
|
+
try:
|
|
69
|
+
raw = p.read_text(encoding="utf-8", errors="replace")
|
|
70
|
+
d = json.loads(raw) if raw.strip() else {}
|
|
71
|
+
if isinstance(d, dict):
|
|
72
|
+
return PolicyProfile.from_dict(d)
|
|
73
|
+
except Exception:
|
|
74
|
+
return PolicyProfile()
|
|
75
|
+
return PolicyProfile()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def save_profile(project_root: Path, profile: PolicyProfile) -> None:
|
|
79
|
+
p = _path(project_root)
|
|
80
|
+
p.write_text(
|
|
81
|
+
json.dumps(profile.to_dict(), ensure_ascii=False, indent=2),
|
|
82
|
+
encoding="utf-8",
|
|
83
|
+
errors="replace",
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def update_profile(
|
|
88
|
+
project_root: Path,
|
|
89
|
+
*,
|
|
90
|
+
files_touched: int,
|
|
91
|
+
tool_calls: int,
|
|
92
|
+
had_shell: bool,
|
|
93
|
+
had_write: bool,
|
|
94
|
+
had_failure: bool,
|
|
95
|
+
alpha: float = 0.08,
|
|
96
|
+
) -> PolicyProfile:
|
|
97
|
+
"""
|
|
98
|
+
Update profile with a single-turn observation.
|
|
99
|
+
|
|
100
|
+
We scale files_touched into [0,1] via min(files/20, 1).
|
|
101
|
+
"""
|
|
102
|
+
prof = load_profile(project_root)
|
|
103
|
+
alpha = _clamp(alpha, 0.01, 0.3)
|
|
104
|
+
ft_scaled = _clamp(float(files_touched) / 20.0, 0.0, 1.0)
|
|
105
|
+
fail = 1.0 if had_failure else 0.0
|
|
106
|
+
shell = 1.0 if had_shell else 0.0
|
|
107
|
+
write = 1.0 if had_write else 0.0
|
|
108
|
+
# tool_calls unused for now, but reserved for future calibration.
|
|
109
|
+
_ = tool_calls
|
|
110
|
+
updated = PolicyProfile(
|
|
111
|
+
failure_rate_ema=_ema(prof.failure_rate_ema, fail, alpha=alpha),
|
|
112
|
+
shell_rate_ema=_ema(prof.shell_rate_ema, shell, alpha=alpha),
|
|
113
|
+
write_rate_ema=_ema(prof.write_rate_ema, write, alpha=alpha),
|
|
114
|
+
files_touched_ema=_ema(prof.files_touched_ema, ft_scaled, alpha=alpha),
|
|
115
|
+
updated_at=int(time.time()),
|
|
116
|
+
)
|
|
117
|
+
save_profile(project_root, updated)
|
|
118
|
+
return updated
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def calibrated_baseline_risk(profile: PolicyProfile) -> float:
|
|
122
|
+
"""
|
|
123
|
+
Convert profile into a baseline risk prior for a repo.
|
|
124
|
+
|
|
125
|
+
Repos with frequent failures, many writes, and lots of files touched tend to
|
|
126
|
+
benefit from higher evidence budgets by default.
|
|
127
|
+
"""
|
|
128
|
+
r = (
|
|
129
|
+
0.55 * profile.failure_rate_ema
|
|
130
|
+
+ 0.20 * profile.write_rate_ema
|
|
131
|
+
+ 0.15 * profile.shell_rate_ema
|
|
132
|
+
+ 0.10 * profile.files_touched_ema
|
|
133
|
+
)
|
|
134
|
+
return _clamp(r, 0.0, 0.8)
|
|
135
|
+
|
|
@@ -395,6 +395,7 @@ async def process_repl_slash(
|
|
|
395
395
|
try:
|
|
396
396
|
risk = float(getattr(cfg, "_risk_score", 0.0) or 0.0)
|
|
397
397
|
pct = getattr(cfg, "_context_percent_left", None)
|
|
398
|
+
prof = getattr(cfg, "_policy_profile", None)
|
|
398
399
|
out(" Dynamic policy:")
|
|
399
400
|
out(f" dynamic_token_policy: {getattr(cfg, 'dynamic_token_policy', True)}")
|
|
400
401
|
out(f" dynamic_risk_policy: {getattr(cfg, 'dynamic_risk_policy', True)}")
|
|
@@ -402,6 +403,12 @@ async def process_repl_slash(
|
|
|
402
403
|
out(f" risk_score: {risk:.2f}")
|
|
403
404
|
if isinstance(pct, int):
|
|
404
405
|
out(f" context_percent_left: {pct}%")
|
|
406
|
+
if isinstance(prof, dict):
|
|
407
|
+
try:
|
|
408
|
+
out(f" profile.failure_rate_ema: {float(prof.get('failure_rate_ema', 0.0) or 0.0):.2f}")
|
|
409
|
+
out(f" profile.files_touched_ema: {float(prof.get('files_touched_ema', 0.0) or 0.0):.2f}")
|
|
410
|
+
except Exception:
|
|
411
|
+
pass
|
|
405
412
|
out()
|
|
406
413
|
except Exception:
|
|
407
414
|
pass
|
|
@@ -314,6 +314,16 @@ def _build_artifact_service(cfg: GemCodeConfig):
|
|
|
314
314
|
|
|
315
315
|
def create_runner(cfg: GemCodeConfig, extra_tools: list | None = None) -> Runner:
|
|
316
316
|
"""Construct Runner + SQLite session service + root LlmAgent."""
|
|
317
|
+
# Load per-repo calibration profile (self-tuning dynamic policy).
|
|
318
|
+
try:
|
|
319
|
+
from gemcode.policy_profile import calibrated_baseline_risk, load_profile
|
|
320
|
+
prof = load_profile(cfg.project_root)
|
|
321
|
+
base = calibrated_baseline_risk(prof)
|
|
322
|
+
cur = float(getattr(cfg, "_risk_score", 0.0) or 0.0)
|
|
323
|
+
object.__setattr__(cfg, "_risk_score", max(cur, base))
|
|
324
|
+
object.__setattr__(cfg, "_policy_profile", prof.to_dict())
|
|
325
|
+
except Exception:
|
|
326
|
+
pass
|
|
317
327
|
modality_tools = build_modality_extra_tools(cfg)
|
|
318
328
|
merged_extra_tools: list | None
|
|
319
329
|
if extra_tools:
|
|
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
|
|
File without changes
|