fix: error state, leg grouping, prompt→generating transition
- log_parser: detect model load failure (child + router patterns) → state=error; switch to generating at progress=1.00 and at prompt eval summary line - frontend: add state-error (llama flashes red, CSS variable override); group each leg+hoof in <g> so walk animation moves hooves with legs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -83,6 +83,8 @@ _PROMPT_SUMMARY_RE = re.compile(
|
||||
)
|
||||
_RELEASE_RE = re.compile(r'slot\s+release:.*stop processing')
|
||||
_UNLOAD_RE = re.compile(r'unload_lru:|unload: stopping model instance')
|
||||
_LOAD_ERROR_RE = re.compile(r'exiting due to model loading error')
|
||||
_EXIT_ERROR_RE = re.compile(r'operator\(\):.*exited with status 1')
|
||||
|
||||
|
||||
# ── State machine ─────────────────────────────────────────────────────────────
|
||||
@@ -121,6 +123,8 @@ class LogParser:
|
||||
return self._set(state="waiting")
|
||||
if _UNLOAD_RE.search(content):
|
||||
return self._set(state="unloading")
|
||||
if _EXIT_ERROR_RE.search(content):
|
||||
return self._set(state="error")
|
||||
return None
|
||||
|
||||
# ── Child-process lines ──────────────────────────────────────────────────
|
||||
@@ -130,6 +134,8 @@ class LogParser:
|
||||
|
||||
if m := _CMD_STATE_RE.match(content):
|
||||
return self._handle_cmd_state(m.group(1))
|
||||
if _LOAD_ERROR_RE.search(content):
|
||||
return self._set(state="error")
|
||||
if _WARMUP_RE.search(content):
|
||||
return self._set(state="warming_up")
|
||||
if _IDLE_RE.search(content):
|
||||
@@ -137,14 +143,14 @@ class LogParser:
|
||||
if _LAUNCH_RE.search(content):
|
||||
return self._set(state="processing_prompt")
|
||||
if m := _PROMPT_TIMING_RE.search(content):
|
||||
progress = float(m.group(2))
|
||||
done = progress >= 1.0
|
||||
metrics = Metrics(
|
||||
prompt_speed=float(m.group(3)),
|
||||
prompt_tokens=int(m.group(1)),
|
||||
prompt_progress=float(m.group(2)),
|
||||
gen_speed=self._state.metrics.gen_speed,
|
||||
n_decoded=self._state.metrics.n_decoded,
|
||||
prompt_progress=None if done else progress,
|
||||
)
|
||||
return self._set(state="processing_prompt", metrics=metrics)
|
||||
return self._set(state="generating" if done else "processing_prompt", metrics=metrics)
|
||||
if m := _GEN_TIMING_RE.search(content):
|
||||
metrics = Metrics(
|
||||
prompt_speed=self._state.metrics.prompt_speed,
|
||||
@@ -154,14 +160,18 @@ class LogParser:
|
||||
)
|
||||
return self._set(state="generating", metrics=metrics)
|
||||
if m := _PROMPT_SUMMARY_RE.search(content):
|
||||
# End-of-slot summary: update prompt speed without changing state.
|
||||
# For short prompts this fires after generating starts (no live prompt line).
|
||||
metrics = Metrics(
|
||||
prompt_speed=float(m.group(2)),
|
||||
prompt_tokens=int(m.group(1)),
|
||||
gen_speed=self._state.metrics.gen_speed,
|
||||
n_decoded=self._state.metrics.n_decoded,
|
||||
)
|
||||
if self._state.state == "processing_prompt":
|
||||
# Summary fires right after prompt eval finishes, before first token.
|
||||
# Advance to generating now rather than waiting for the first tg line.
|
||||
# For short prompts the summary arrives after generating has already
|
||||
# started, so the guard prevents stepping back.
|
||||
return self._set(state="generating", metrics=metrics)
|
||||
return self._set(metrics=metrics)
|
||||
if _RELEASE_RE.search(content):
|
||||
return self._set(
|
||||
|
||||
Reference in New Issue
Block a user