From ef476c105882ac07620b8bb34fe023ca76dc1b5e Mon Sep 17 00:00:00 2001 From: Ed_ Date: Thu, 11 Jun 2026 23:35:27 -0400 Subject: [PATCH] docs(ai_client): document Result API + deprecation --- docs/guide_ai_client.md | 90 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/docs/guide_ai_client.md b/docs/guide_ai_client.md index eb2dc6ed..91e2d88d 100644 --- a/docs/guide_ai_client.md +++ b/docs/guide_ai_client.md @@ -174,7 +174,13 @@ ai_client.clear_comms_log() # Clear ai_client.get_token_stats(md_content) # Estimate token usage ``` -### Provider Error Taxonomy +### Provider Error Taxonomy — Legacy (Pre-Refactor) + +> **As of 2026-06-11:** This section describes the pre-refactor exception-based +> pattern. The `ProviderError` class is **removed** in the +> `data_oriented_error_handling_20260606` track. See the new +> [Data-Oriented Error Handling (Fleury Pattern)](#data-oriented-error-handling-fleury-pattern) +> section below for the current convention. ```python class ProviderError(Exception): @@ -186,7 +192,12 @@ class ProviderError(Exception): """Returns a user-friendly error message.""" ``` -`ProviderError` is raised by provider-specific `_send_*` functions on failure. The caller (typically `app_controller.py`) catches it and surfaces the error to the user via `app.ai_status`. +`ProviderError` was raised by provider-specific `_send_*` functions on failure. +The caller (typically `app_controller.py`) caught it and surfaced the error to +the user via `app.ai_status`. Post-refactor, the same flow uses `ErrorInfo` +dataclasses inside `Result[str]` returns — see the new section below. + +--- --- @@ -426,6 +437,81 @@ def test_send_routes_to_provider(monkeypatch): Gated by env var (e.g., `RUN_REAL_AI_TESTS=1`). Hits the real API. Not in default CI. +## Data-Oriented Error Handling (Fleury Pattern) + +The provider layer follows the "errors are just cases" framework +(Ryan Fleury, [The Easiest Way To Handle +Errors](https://www.dgtlgrove.com/p/the-easiest-way-to-handle-errors)). The +canonical reference is +[`conductor/code_styleguides/error_handling.md`](../conductor/code_styleguides/error_handling.md). + +### Result-Based Returns + +All `_send__result()` functions (8 vendors: Gemini, Anthropic, +DeepSeek, MiniMax, Gemini CLI, Qwen, Llama, Grok — plus the +`_send_llama_native` Ollama adapter) return `Result[str, ErrorInfo]`. SDK +exceptions are caught at the boundary (`src/openai_compatible.py`, +`src/qwen_adapter.py`) and converted to `ErrorInfo` dataclasses. The +`_classify__error()` functions return `ErrorInfo` (not raise +`ProviderError`, which has been removed). + +The 12 canonical `ErrorKind` values: `NETWORK`, `AUTH`, `QUOTA`, +`RATE_LIMIT`, `BALANCE`, `PERMISSION`, `NOT_FOUND`, `INVALID_INPUT`, +`NOT_READY`, `UNKNOWN`, `CONFIG`, `INTERNAL`. Each has exactly one +meaning — do not overload `UNKNOWN` when a new failure mode surfaces +(Lottes's anti-pattern). `ErrorInfo.source` is one of +`"ai_client."` (e.g., `"ai_client.gemini"`, +`"ai_client.anthropic"`) for diagnostic routing. + +### Public API + +- **`ai_client.send_result(...)`** — the new public API. Returns + `Result[str, ErrorInfo]`. Mirrors the `send()` signature (13+ + parameters including 8 callbacks). Internally calls + `_send__result()` for the active provider. +- **`ai_client.send(...)`** — **deprecated.** Emits `DeprecationWarning` + at runtime (via `typing_extensions.deprecated`; cached per call site to + avoid log spam). Returns `str` (the response text) for backward compat. + Errors are logged to the comms log via the deprecated path's comms entry + but not returned. Will be removed in the `public_api_migration_20260606` + follow-up track. + +### Example + +```python +from src import ai_client +from src.result_types import ErrorKind + +r = ai_client.send_result("system prompt", "user message") +if not r.ok: + for err in r.errors: + log.error(err.ui_message()) + # err.kind is one of ErrorKind.*; err.source is "ai_client." +# use r.data regardless (it's the zero-initialized "" on failure) +print(r.data) +``` + +### Migration Notes for Existing Callers + +- The `app_controller._api_generate` path and the MMA worker dispatch + (`multi_agent_conductor.py:591`) call `ai_client.send()`. They will + continue to work during the deprecation window; migration to + `send_result()` is the work of the `public_api_migration_20260606` + follow-up track. +- Tests that mock `ai_client._send_` should be updated to mock + `_send__result()` (or `send_result()` at the public API level). +- `tests/conftest.py` adds a `filterwarnings` entry to silence the + `DeprecationWarning` from `send()` during the transition; new tests + for the new API should assert the warning is **not** emitted by + `send_result()`. + +### See Also (in-doc) + +- [`conductor/code_styleguides/error_handling.md`](../conductor/code_styleguides/error_handling.md) — canonical styleguide (5 patterns, data model, decision tree, anti-patterns) +- [`conductor/tracks/data_oriented_error_handling_20260606/spec.md`](../conductor/tracks/data_oriented_error_handling_20260606/spec.md) — the spec that introduced this pattern +- [`docs/guide_mcp_client.md`](guide_mcp_client.md#data-oriented-error-handling-fleury-pattern) — same pattern in the MCP tool layer +- [`docs/guide_rag.md`](guide_rag.md#data-oriented-error-handling-fleury-pattern) — same pattern in the RAG engine + --- ## See Also