Skip to content

Commit c62f9ee

Browse files
committed
chore(agents): add session log
1 parent ab21c70 commit c62f9ee

1 file changed

Lines changed: 41 additions & 0 deletions

File tree

.agents/2026-08-03.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,44 @@ Character-count logging for LLM invocations, per-vector-store retrieval settings
4343

4444
- Commits today: `615c684` chars logging, `1d76058`/`56ef54a`/`1bfc9fb` per-store k + tests, `9a8d56a`/`f31dcea` docs + config updates, `f590af5` logging standardization.
4545
- `utils_pkg/AGENTS.md` example updated from `setup_logging` -> `setup_root_logger` (uncommitted).
46+
47+
---
48+
49+
## Session 2: HuggingFace token-window / max-token handling, invocation error handling, and frontend error display
50+
51+
**Authoring agent:** opencode
52+
53+
## Objective
54+
55+
Fix HuggingFace providers reserving the entire context window as output when `max_tokens` is unset (causing spurious ~1M output-window reports and rate limiting), handle invocation errors adaptively, and stop rendering backend errors as chat bubbles in the frontend. Steps 1-4 done; Step 5 (frontend) pending.
56+
57+
## Completed
58+
59+
1. **models.dev catalog client** (`models_catalog.py`): lazy fetch of the models.dev api.json with in-memory + 1-day on-disk cache, offline fallback, graceful `None` for providers/models missing from the catalog.
60+
2. **Invocation error classification**: `LLMInvocationErrorCategory` enum (errors.py) + `classify_llm_invocation_error()` (llm.py) -- tolerant regex classifiers with cause-chain unwrapping. `looks_like_structured_output_error` folded into the `STRUCTURED_OUTPUT_REJECTED` category.
61+
3. **Always-bounded max output tokens**: every invoke now gets a finite, clamped max-output param. `resolve_output_token_limit()` resolves explicit param -> generic `max_output_tokens` -> per-role fallback, then clamps to catalog `limit.output` and to `context - estimated input` (chars//4), since HF applies a **total budget** (input + output <= context). `LLMModel.provider_defaults` (Layer 4) + optional `providers` config section; `_provider_defaults_for_role` shared on `BaseLangGraph`. Per-node `max_output_tokens` added to RAG/shared node `model_defaults`; code-pkg deferred to the `plan` role default.
62+
4. **Adaptive retry** in `BaseLLMNode`: `CONTEXT_OVERFLOW` shrinks the output window and retries (<=3x); `finish_reason="length"` grows it and retries (<=2x); rate-limit and other errors re-raise immediately. Bails when the window cannot move.
63+
64+
## Errors and Lessons
65+
66+
- **Do not reuse tenacity for this retry.** Tenacity (api, mcp tools) retries the *identical* call with backoff; our retry must change parameters between attempts, which tenacity's decorator cannot do cleanly. Backoff is also most useful for rate-limit retries, which we deliberately surface.
67+
- **`ChatHuggingFace` uses `max_tokens`** (mapped internally to `max_new_tokens`), not `max_new_tokens` -- only ollama is `num_predict`. Using `max_new_tokens` gets stripped by provider field filtering. Verify against the installed provider class.
68+
- **Resolver "explicit wins" precedence bit the retry**: setting the generic `max_output_tokens` key while a stale explicit `max_tokens` was present meant the window never changed; fix is to set the provider token param directly, then re-clamp.
69+
- Async tests must NOT inherit `unittest.TestCase` (pytest-asyncio auto mode silently skips those coroutines).
70+
- Pre-existing unrelated failures unchanged: utils_pkg 6 (api-router 422s, stores-retrieval env var), rag_pkg 2 (tools_picker display).
71+
- `ty` diagnostics went 50 -> 46 (added missing type annotations to `klea_code.py`).
72+
73+
## Notes
74+
75+
- HF's total-budget behavior is why output must always be bounded and clamped against `context - input`.
76+
- `deployments/huggingface` submodule dirt and `VECTOR_STORES_IGNORED` remain the user's local disposition.
77+
78+
## Next session
79+
80+
1. **Step 5: errors out of the chat pane**
81+
- `api/chat.py`: `/query/stream` emits a structured `error` event (`message`, `error_type`, `node`) and stops storing errors as assistant messages; `/query` drops the error `store.add_message` too.
82+
- `ui/web/nicegui/runner.py` `_do_stream`: `error` events + `httpx.RequestError` -> `ui.notification` toasts, never chat bubbles.
83+
- `ui/tui/repl.py`: errors to stderr, not the AI response.
84+
- Tests: extend `test_api_routers.py` for the error event shape + nothing persisted.
85+
2. **Step 6: docs/config + verification** -- example configs demonstrating the `providers` section, tutorial docs, full verification.
86+
3. Optional follow-ups (out of scope): history-size-based memory summarisation on context overflow, code-pkg per-node `max_output_tokens` tuning.

0 commit comments

Comments
 (0)