You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PR-3E-2c. Adds the raise-on-failure contract that tranche 2 deferred, then
migrates the 4 sites that MUST fail loud.
New: codec_llm.LLMError + codec_llm.call(raise_on_error=True). When True, call()
raises LLMError on EVERY non-success path — non-200 (after retries), request
exception (after retries), and a 200 with empty/unparseable content. Default
stays False (never-raise -> ""), so the existing streaming/best-effort callers
(codec.py, qwen_call, compaction, dictate) are untouched — pinned by a
regression guard test.
Migrated:
- codec_textassist.call_qwen -> call(raise_on_error=True). Fixes a real bug: on
LLM failure the never-raise path would pbcopy "" + Cmd-V, pasting EMPTY over
the user's selection and showing "Text replaced!". Now the caller's except
shows the Error overlay (also on empty-200). FINAL-ANSWER strip kept at the
call site; <think> strip now handled by codec_llm.
- scripts/regen_skill_descriptions._llm -> call(raise_on_error=True). Fail-loud
preserved (LLMError propagates like the old raise_for_status; empty-200 now
raises instead of writing an empty description).
- codec_agent_plan._qwen_chat + codec_agent_runner._qwen_chat -> call(
raise_on_error=True) behind a thin adapter that maps LLMError onto their
PUBLIC QwenUnavailableError, so the daemon's `except QwenUnavailableError`
retry/abort/resume logic is unchanged. Added a parallel _qwen_base() resolver
(call-time config). These also gain <think> strip + enable_thinking=False ->
more robust JSON parsing downstream.
Tests: tests/test_llm_raise_mode.py (14 — raise-mode success/non-200/exception/
empty-200, default-still-never-raises regression guard, agent adapters map to
QwenUnavailableError + pass content through, source invariants). 109 agent
tests (test_agent_plan/runner/chat_plan_persistence) still green. Full suite
1423 passing, 23 known-baseline failures, zero new. Zero net-new ruff (per-file
delta vs origin/main = 0). No skills/ touched -> no manifest regen.
Co-authored-by: Mickael Farina <farina.mickael@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Other engine modules (`codec_overlays`, `codec_metrics`, `codec_logging`, `codec_gdocs`, `codec_google_auth`, `codec_cdp`, `codec_llm_proxy`, `codec_retry`, `codec_alerts`, `codec_search`, `codec_textassist`, `codec_watcher`, `codec_watchdog`) are internal helpers — read them when you need them, but they're not part of the navigation surface for an agent making structural changes. (Keyboard handling — wake word, F13 toggle, F18 voice, double-tap — lives **inline in `codec.py`** in the `codec` PM2 process; the old standalone `codec_keyboard.py` was deleted as a dead duplicate per A-8.)
58
58
59
-
**Canonical LLM + vision helpers (PR-3E, A-11/A-12).** `codec_vision.py` is the SINGLE source for screen-vision (`describe_sync` / `describe_async`, Gemini-flash → local-Qwen-VL fallback, config read live from `codec_config`) — used by `codec.py`, `codec_voice`, `codec_session`. `codec_llm.py` is the canonical chat/completions caller (`call()` + `strip_think`/`extract_content` — headers, Bearer auth, `enable_thinking`, `<think>` strip, `choices/reasoning` parse, retry+backoff, never-raises). NOTE: `codec_llm_proxy.py` is a priority *queue* (semaphore), NOT an HTTP caller — don't confuse the two. A-12 is migrating the ~45 inline `chat/completions` sites onto `codec_llm` in phased tranches. Done: `codec_llm.call()` (non-stream) + `stream()` (sync SSE generator, yields raw deltas, never-raises); migrated sites = codec.py voice-reply, `codec_session.qwen_call` + `qwen_stream`, `codec_compaction`, `codec_dictate`. Pending tranches: 2c raise-mode (`codec_llm.call(raise_on_error=True)` for agent_plan/runner + textassist + the regen script — they MUST fail loud, never-raise would silently paste empty / write empty), an async `astream()` for voice `_stream_qwen` + agents (queue stays at the call site — `codec_llm` never owns the semaphore), dashboard (4 non-stream + the `[SKILL:…]` stream tag-machine, which keeps its own parser and consumes only `stream()`'s raw tokens), bridges, and a skills tranche.
59
+
**Canonical LLM + vision helpers (PR-3E, A-11/A-12).** `codec_vision.py` is the SINGLE source for screen-vision (`describe_sync` / `describe_async`, Gemini-flash → local-Qwen-VL fallback, config read live from `codec_config`) — used by `codec.py`, `codec_voice`, `codec_session`. `codec_llm.py` is the canonical chat/completions caller (`call()` + `strip_think`/`extract_content` — headers, Bearer auth, `enable_thinking`, `<think>` strip, `choices/reasoning` parse, retry+backoff, never-raises). NOTE: `codec_llm_proxy.py` is a priority *queue* (semaphore), NOT an HTTP caller — don't confuse the two. A-12 is migrating the ~45 inline `chat/completions` sites onto `codec_llm` in phased tranches. Done: `codec_llm.call()` (non-stream; + `raise_on_error=True` raising `codec_llm.LLMError` for fail-loud callers) + `stream()` (sync SSE generator, yields raw deltas, never-raises); migrated sites = codec.py voice-reply, `codec_session.qwen_call` + `qwen_stream`, `codec_compaction`, `codec_dictate`, `codec_textassist`, the regen script, and `codec_agent_plan`/`codec_agent_runner` `_qwen_chat` (adapter maps `LLMError` → their public `QwenUnavailableError`). Pending tranches: an async `astream()` for voice `_stream_qwen` + agents `Agent.run` (queue stays at the call site — `codec_llm` never owns the semaphore), dashboard (4 non-stream + the `[SKILL:…]` stream tag-machine, which keeps its own parser and consumes only `stream()`'s raw tokens), bridges, and a skills tranche.
Copy file name to clipboardExpand all lines: codec_textassist.py
+13-9Lines changed: 13 additions & 9 deletions
Original file line number
Diff line number
Diff line change
@@ -24,15 +24,19 @@ def call_qwen(text, mode):
24
24
"translate": "You are a translator. Translate the following text into English. No matter what language the input is — Ukrainian, Spanish, French, Russian, Chinese, Arabic, anything — always translate to English. Output ONLY the translated English text, nothing else.",
25
25
"prompt": "You are a prompt engineer. Rewrite the following text to be a clear, optimized prompt for an AI language model. Make it specific, structured, and effective. Remove ambiguity, add context where helpful, and ensure the intent is crystal clear. Output ONLY the optimized prompt, nothing else."
0 commit comments