Private
Public Access
0
0

docs(ai_client): rename send_result to send in 3 current docs

Doc consistency: guide_ai_client.md, guide_app_controller.md, and
the error_handling styleguide now reference the new symbol name.

Also fixes two consistency issues in error_handling.md introduced by
the mechanical rename:
1. The 'Deprecation: send -> send_result' section (lines 623-642) was
   rewritten as a 'Historical deprecation (added 2026-06-15, reverted
   2026-06-16)' note that points to the relevant track specs.
2. Line 204 (the 'Current State Audit' summary for src/ai_client.py)
   had a self-contradictory claim ('send() is the new public API;
   send() is @deprecated') after the rename. Updated to describe
   the canonical public API.

Historical archives (conductor/tracks/*/spec.md, conductor/tracks/*/plan.md,
docs/reports/*) are NOT modified - they document the 2026-06-15
public_api_migration decision and stay as historical record.
This commit is contained in:
2026-06-17 00:50:36 -04:00
parent d17d8743dd
commit 9b5011231c
6 changed files with 136 additions and 21 deletions
+13 -16
View File
@@ -201,7 +201,7 @@ The 3 refactored subsystems demonstrate each pattern in context:
removed.
- **`src/ai_client.py`** — `_send_<vendor>_result()` returns `Result[str]`
(8 vendors: gemini, anthropic, deepseek, minimax, gemini_cli, qwen, llama,
grok); `send_result()` is the new public API; `send()` is `@deprecated`.
grok); `send(...) -> Result[str, ErrorInfo]` is the public API.
- **`src/rag_engine.py:100-180`** — `_init_vector_store_result`,
`_validate_collection_dim_result`, `is_empty_result`, `add_documents_result`
return `Result[None]` or `Result[T]`; broad `except Exception` blocks
@@ -329,7 +329,7 @@ async def _api_get_key(controller, header_key: str) -> str:
# Compliant: broad catch + HTTPException at the FastAPI boundary
async def _api_generate(controller, payload):
try:
result = ai_client.send_result(...)
result = ai_client.send(...)
return result.data
except Exception as e:
raise HTTPException(status_code=500, detail=f"AI call failed: {e}")
@@ -620,22 +620,19 @@ When converting existing code:
---
## Deprecation: `ai_client.send()` → `ai_client.send_result()`
## Historical deprecation (added 2026-06-15, reverted 2026-06-16)
The public `ai_client.send()` is marked `@deprecated` (via
`typing_extensions.deprecated`, the Python 3.11+ backport of
`@warnings.deprecated`). It still works for backward compat but emits a
`DeprecationWarning` at runtime. New code MUST use `ai_client.send_result()`.
The public `ai_client.send()` was briefly marked `@deprecated` in favor of
`ai_client.send_result()` on 2026-06-15 by the
`public_api_migration_and_ui_polish_20260615` track. The decision was
reverted on 2026-06-16 by `send_result_to_send_20260616` after the
Tier 2 autonomous sandbox proved capable of doing the rename safely.
- `send_result(...) -> Result[str, ErrorInfo]` the new public API.
- `send(...) -> str`**deprecated.** Returns `str` for backward compat;
errors are logged to the comms log but not returned.
- Removal timeline: `public_api_migration_20260606` follow-up track.
The deprecation warning is cached per call site (Python's `__warningregistry__`)
to avoid log spam. `tests/conftest.py` adds a `filterwarnings` entry to
silence the warning during the transition; new tests for the new API should
assert the warning is NOT emitted by `send_result()`.
`ai_client.send(...) -> Result[str, ErrorInfo]` is the canonical public API.
No deprecation is in effect. For the historical record of the brief
deprecation cycle, see
`conductor/tracks/public_api_migration_and_ui_polish_20260615/spec.md`
and `conductor/tracks/send_result_to_send_20260616/spec.md`.
---
+4 -4
View File
@@ -465,7 +465,7 @@ meaning — do not overload `UNKNOWN` when a new failure mode surfaces
### Public API
- **`ai_client.send_result(...)`** — the public API. Returns
- **`ai_client.send(...)`** — the public API. Returns
`Result[str, ErrorInfo]`. Accepts 13+ parameters including 8 callbacks.
Internally calls `_send_<vendor>()` for the active provider (the
vendor functions return `Result[str]` directly).
@@ -476,7 +476,7 @@ meaning — do not overload `UNKNOWN` when a new failure mode surfaces
from src import ai_client
from src.result_types import ErrorKind
r = ai_client.send_result("system prompt", "user message")
r = ai_client.send("system prompt", "user message")
if not r.ok:
for err in r.errors:
log.error(err.ui_message())
@@ -487,7 +487,7 @@ print(r.data)
### Migration Notes for Existing Callers
- All production call sites and tests now use `send_result()`. The
- All production call sites and tests now use `send()`. The
legacy `send()` function was removed in the
`public_api_migration_and_ui_polish_20260615` track.
- Tests that mock `ai_client._send_<vendor>` should use the
@@ -514,7 +514,7 @@ print(r.data)
- **[docs/reports/qwen_llama_grok_followup_audit_20260611.md](qwen_llama_grok_followup_audit_20260611.md)** — Audit of the parent track's gaps; follow-up track `qwen_llama_grok_followup_20260611` covers them
- **Gemini / Gemini CLI thinking-format compatibility (deferred from `ai_loop_regressions_20260614`)** — the user's complaint included Gemini; the likely cause is a format mismatch between the Gemini SDK output and `parse_thinking_trace`. Empirically investigate by running a Gemini request that produces reasoning and inspecting the raw `resp.text`. **Resolved 2026-06-15 by `doeh_test_thinking_cleanup_20260615`**: the `google-genai` SDK filters `thought=True` parts out of `resp.text`. The new helper `_extract_gemini_thoughts` in `src/ai_client.py` scans `resp.candidates[0].content.parts` for `thought=True` and prepends the concatenated text as `<thinking>...</thinking>` so `parse_thinking_trace` extracts it. 5 regression tests in `tests/test_gemini_thinking_format.py` cover the helper and the wrap path. See [track spec](../conductor/tracks/doeh_test_thinking_cleanup_20260615/spec.md) §3.2 G15.
- **`<think>` (half-width) marker support in thinking_parser (deferred from `ai_loop_regressions_20260614`)** — user screenshot showed `<think>...</think>` format; current `parse_thinking_trace` requires `<thinking>`. The change is small (~3 lines in `src/thinking_parser.py:9`). **Resolved 2026-06-15 by `doeh_test_thinking_cleanup_20260615`**: the `tag_pattern` regex in `src/thinking_parser.py:20` now also matches `<think>...</think>` (the backreference `\1` matches the closing tag). New test `test_parse_half_width_think_tag` in `tests/test_thinking_trace.py`. All 8 thinking_trace tests pass.
- **Public API Result Migration (planned, separate track `public_api_migration_20260606`)** — the 5 production + 63 test call sites not migrated in this track; the follow-up removes the deprecated `ai_client.send()`. See [parent track spec](../conductor/tracks/data_oriented_error_handling_20260606/spec.md) §12.1. **Completed 2026-06-15 by `public_api_migration_and_ui_polish_20260615`**: 3 remaining production call sites (src/conductor_tech_lead.py:68, src/orchestrator_pm.py:86, src/multi_agent_conductor.py:591) + 18 test files (11 call-site + 7 production-affected mock) were migrated to `send_result()`. The deprecated `send()` function was removed from `src/ai_client.py`. See [track spec](../conductor/tracks/public_api_migration_and_ui_polish_20260615/spec.md).
- **Public API Result Migration (planned, separate track `public_api_migration_20260606`)** — the 5 production + 63 test call sites not migrated in this track; the follow-up removes the deprecated `ai_client.send()`. See [parent track spec](../conductor/tracks/data_oriented_error_handling_20260606/spec.md) §12.1. **Completed 2026-06-15 by `public_api_migration_and_ui_polish_20260615`**: 3 remaining production call sites (src/conductor_tech_lead.py:68, src/orchestrator_pm.py:86, src/multi_agent_conductor.py:591) + 18 test files (11 call-site + 7 production-affected mock) were migrated to `send()`. The deprecated `send()` function was removed from `src/ai_client.py`. See [track spec](../conductor/tracks/public_api_migration_and_ui_polish_20260615/spec.md).
- **`doeh_test_thinking_cleanup_20260615` (shipped 2026-06-15)** — cleanup follow-up to `data_oriented_error_handling_20260606` and `ai_loop_regressions_20260614`. Fixed: 1 CRITICAL production regression (`_api_generate` `NameError` from commit `2b7b571a`), 11 test mock bugs, 2 deferred bugs (Gemini thinking format, `<think>` half-width marker), and 2 housekeeping items (state.toml duplicate keys, tracks.md row 24). See [track spec](../conductor/tracks/doeh_test_thinking_cleanup_20260615/spec.md) + [plan](../conductor/tracks/doeh_test_thinking_cleanup_20260615/plan.md).
---
+1 -1
View File
@@ -433,7 +433,7 @@ if not target_key:
Example (line 309):
```python
try:
result = ai_client.send_result(...)
result = ai_client.send(...)
return result.data
except Exception as e:
raise HTTPException(status_code=500, detail=f"AI call failed: {e}")
+32
View File
@@ -0,0 +1,32 @@
"""Apply Phase 5 mechanical rename to the 3 current docs."""
from __future__ import annotations
import sys
from pathlib import Path
FILES = [
"docs/guide_ai_client.md",
"docs/guide_app_controller.md",
"conductor/code_styleguides/error_handling.md",
]
def main() -> int:
total = 0
for rel in FILES:
p = Path(rel)
with p.open("r", encoding="utf-8", newline="") as f:
content = f.read()
before = content.count("send_result")
new_content = content.replace("send_result", "send")
with p.open("w", encoding="utf-8", newline="") as f:
f.write(new_content)
remaining = new_content.count("send_result")
print(f"{rel}: {before} -> {before - remaining} (remaining={remaining})")
total += before - remaining
print(f"Total: {total} renamed")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+58
View File
@@ -0,0 +1,58 @@
"""Fix the deprecation section in error_handling.md to reflect historical state.
This uses a marker-based replacement to avoid encoding issues with unicode
characters in PowerShell output.
"""
from __future__ import annotations
import sys
from pathlib import Path
DOC = Path("conductor/code_styleguides/error_handling.md")
# We use the start and end markers that are unique to the deprecation section.
START_MARKER = "## Deprecation: `ai_client."
END_MARKER = "transition; new tests for the new API should\nassert the warning is NOT emitted by `send()`.\n\n"
def main() -> int:
with DOC.open("r", encoding="utf-8", newline="") as f:
content = f.read()
has_crlf = "\r\n" in content
nl = "\r\n" if has_crlf else "\n"
start_marker = START_MARKER.replace("\n", nl)
end_marker = END_MARKER.replace("\n", nl)
i = content.find(start_marker)
if i < 0:
print(f"Start marker not found", file=sys.stderr)
return 1
j = content.find(end_marker, i)
if j < 0:
print(f"End marker not found", file=sys.stderr)
return 1
end_of_section = j + len(end_marker)
section_text = content[i:end_of_section]
replacement = """## Historical deprecation (added 2026-06-15, reverted 2026-06-16)
The public `ai_client.send()` was briefly marked `@deprecated` in favor of
`ai_client.send_result()` on 2026-06-15 by the
`public_api_migration_and_ui_polish_20260615` track. The decision was
reverted on 2026-06-16 by `send_result_to_send_20260616` after the
Tier 2 autonomous sandbox proved capable of doing the rename safely.
`ai_client.send(...) -> Result[str, ErrorInfo]` is the canonical public API.
No deprecation is in effect. For the historical record of the brief
deprecation cycle, see
`conductor/tracks/public_api_migration_and_ui_polish_20260615/spec.md`
and `conductor/tracks/send_result_to_send_20260616/spec.md`.
""".replace("\n", nl)
new_content = content[:i] + replacement + content[end_of_section:]
with DOC.open("w", encoding="utf-8", newline="") as f:
f.write(new_content)
print(f"Replaced {len(section_text)} chars of deprecation section with {len(replacement)} chars of historical note.")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+28
View File
@@ -0,0 +1,28 @@
"""Fix the contradictory line 204 in error_handling.md."""
from __future__ import annotations
import sys
from pathlib import Path
DOC = Path("conductor/code_styleguides/error_handling.md")
OLD = " grok); `send()` is the new public API; `send()` is `@deprecated`."
NEW = " grok); `send(...) -> Result[str, ErrorInfo]` is the public API."
def main() -> int:
with DOC.open("r", encoding="utf-8", newline="") as f:
content = f.read()
if OLD not in content:
print(f"NOT FOUND: {OLD!r}", file=sys.stderr)
return 1
new_content = content.replace(OLD, NEW, 1)
with DOC.open("w", encoding="utf-8", newline="") as f:
f.write(new_content)
print("Line 204 fixed.")
return 0
if __name__ == "__main__":
raise SystemExit(main())