Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
"""In-session context growth for the managed llama.cpp runtime.
|
||||
|
||||
The live half of the window ladder (context_policy.growth_decision): when a
|
||||
session reaches the edge of its granted window, Hermes grows the window
|
||||
toward the model's native max INSTEAD of compressing. Compression becomes
|
||||
what the design says it is — the move of last resort, once the window is at
|
||||
native (or the speed floor / physics say stop).
|
||||
|
||||
Mechanism: growth is re-prefill. A per-model window
|
||||
override is persisted, presets regenerate with the bigger window, the
|
||||
supervised server bounces, and the next request autoloads the model at the
|
||||
new window and re-prefills the conversation. Nothing about the Hermes
|
||||
conversation mutates — no prompt-cache or role-alternation risk; the whole
|
||||
operation is server-side.
|
||||
|
||||
Scope guard: only a server THIS process supervises grows. Detected external
|
||||
servers and other-process supervisors keep their own policies.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def window_overrides_path():
|
||||
from hermes_cli.local_runtime.binaries import runtimes_root
|
||||
|
||||
return runtimes_root() / "window_overrides.json"
|
||||
|
||||
|
||||
def load_window_overrides() -> dict:
|
||||
"""model_id -> granted window (int). Empty on any read problem."""
|
||||
try:
|
||||
with open(window_overrides_path(), encoding="utf-8") as fh:
|
||||
data = json.load(fh)
|
||||
return {str(k): int(v) for k, v in data.items()}
|
||||
except Exception: # noqa: BLE001
|
||||
return {}
|
||||
|
||||
|
||||
def save_window_override(model_id: str, window: int) -> None:
|
||||
overrides = load_window_overrides()
|
||||
overrides[model_id] = int(window)
|
||||
path = window_overrides_path()
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(overrides, indent=1), encoding="utf-8")
|
||||
|
||||
|
||||
def clear_window_override(model_id: str) -> None:
|
||||
"""Drop a model's growth state (delete/re-download paths)."""
|
||||
overrides = load_window_overrides()
|
||||
if model_id in overrides:
|
||||
del overrides[model_id]
|
||||
window_overrides_path().write_text(
|
||||
json.dumps(overrides, indent=1), encoding="utf-8")
|
||||
|
||||
|
||||
def is_managed_endpoint(base_url: str) -> bool:
|
||||
"""True when base_url is the server this process's state file points at."""
|
||||
try:
|
||||
from hermes_cli.local_runtime.endpoint import _state_endpoint
|
||||
|
||||
state = _state_endpoint()
|
||||
if state is None:
|
||||
return False
|
||||
return (base_url or "").rstrip("/") == str(
|
||||
state.get("base_url", "")).rstrip("/")
|
||||
except Exception: # noqa: BLE001
|
||||
return False
|
||||
|
||||
|
||||
def maybe_grow_window(model_id: str, *, base_url: str, session_tokens: int,
|
||||
current_window: int,
|
||||
measured_decode_tok_s: float | None = None) -> int | None:
|
||||
"""One growth evaluation + execution. Returns the NEW window when the
|
||||
ladder granted a bigger one, else None (hold / compress / not ours).
|
||||
|
||||
The caller sits at a request boundary by construction (the pre-API
|
||||
compression gate), so re-prefill growth is safe at any call: the next
|
||||
request rebuilds server state from scratch in the larger window —
|
||||
nothing rewinds.
|
||||
"""
|
||||
from hermes_cli.local_runtime.bootstrap import (
|
||||
get_supervisor,
|
||||
refresh_local_runtime,
|
||||
staged_models,
|
||||
)
|
||||
from hermes_cli.local_runtime.context_policy import growth_decision
|
||||
from hermes_cli.local_runtime.estimator import profile_from_gguf
|
||||
from hermes_cli.local_runtime.gguf import read_gguf_header
|
||||
from hermes_cli.local_runtime.hardware import probe_budget
|
||||
|
||||
sup = get_supervisor()
|
||||
if sup is None or not is_managed_endpoint(base_url):
|
||||
return None
|
||||
|
||||
gguf = next((p for p in staged_models()
|
||||
if p.stem.startswith(model_id) or model_id in p.stem), None)
|
||||
if gguf is None:
|
||||
return None
|
||||
|
||||
try:
|
||||
profile = profile_from_gguf(read_gguf_header(gguf))
|
||||
except (ValueError, OSError) as exc:
|
||||
logger.debug("growth skip %s: unreadable gguf (%s)", model_id, exc)
|
||||
return None
|
||||
|
||||
try:
|
||||
server_idle = sup.is_idle(model_id)
|
||||
except Exception: # noqa: BLE001
|
||||
server_idle = False
|
||||
|
||||
decision = growth_decision(
|
||||
# Capacity budget, not live-free: growth executes via a server
|
||||
# bounce, so the grown instance loads onto a freed card. Live-free
|
||||
# here is distorted by the very model being grown — it reads its
|
||||
# own residency as unavailable and vetoes rungs that fit.
|
||||
profile, probe_budget(planning=True),
|
||||
current_window=current_window,
|
||||
session_tokens=session_tokens,
|
||||
measured_decode_tok_s=measured_decode_tok_s,
|
||||
server_idle=server_idle,
|
||||
# The caller IS the occupancy signal: this runs from the agent's
|
||||
# compression gate, which fired on its own threshold. Two
|
||||
# separately-derived edges must not deadlock into
|
||||
# compress-before-grow.
|
||||
occupancy_confirmed=True,
|
||||
)
|
||||
if decision.action != "grow" or not decision.next_window:
|
||||
logger.debug("growth %s: %s (%s)", model_id, decision.action, decision.reason)
|
||||
return None
|
||||
|
||||
logger.info("context growth %s: %s", model_id, decision.reason)
|
||||
save_window_override(model_id, decision.next_window)
|
||||
if not refresh_local_runtime():
|
||||
# The override still lands at the next boot; report no growth NOW
|
||||
# so the caller compresses instead of overflowing a stale window.
|
||||
logger.warning("growth %s: server refresh failed; compression proceeds", model_id)
|
||||
return None
|
||||
return decision.next_window
|
||||
Reference in New Issue
Block a user