Private
Public Access
0
0

feat(audit): add scripts/audit_no_inline_tool_loops.py + state.toml Phase 1 progress

Task 1.8 (the plan's numbering: 'Add audit script'). Audit checks
that no _send_<vendor> in src/ai_client.py contains an inline
'for round_idx in range(MAX_TOOL_ROUNDS' loop. The audit excludes
the 4 vendored-call-path vendors (anthropic, gemini, gemini_native,
deepseek) which are documented in state.toml's deferred_work
section as future work (they use their own SDKs and need
separate per-vendor conversion to OpenAICompatibleRequest).

state.toml:
- t1_7 (Apply to 4 inline-loop vendors): completed for
  _send_gemini_cli only. Anthropic + Gemini + DeepSeek deferred.
- t1_8 (Add audit script): in_progress.
- t1_7 reuses commit 4748d134 (the send_func + on_pre_dispatch
  refactor that introduced the new helper pattern for
  vendored call paths).

OK: audit passes against the current 4 OpenAI-compat vendors
(minimax, grok, llama, qwen still uses _dashscope_call but
has no inline loop) + gemini_cli.
This commit is contained in:
2026-06-11 16:17:23 -04:00
parent 9ddfa98133
commit 7e4503f4e8
2 changed files with 45 additions and 2 deletions
@@ -28,8 +28,8 @@ t1_3 = { status = "completed", commit_sha = "1c836647", description = "Red: 5 te
t1_4 = { status = "completed", commit_sha = "19a4d43e", description = "Green: implement run_with_tool_loop in src/ai_client.py" } t1_4 = { status = "completed", commit_sha = "19a4d43e", description = "Green: implement run_with_tool_loop in src/ai_client.py" }
t1_5 = { status = "completed", commit_sha = "19a4d43e", description = "Apply to _send_minimax (replace inline loop)" } t1_5 = { status = "completed", commit_sha = "19a4d43e", description = "Apply to _send_minimax (replace inline loop)" }
t1_6 = { status = "completed", commit_sha = "4069d677", description = "Apply to _send_grok + _send_llama (Qwen deferred: uses _dashscope_call, not send_openai_compatible)" } t1_6 = { status = "completed", commit_sha = "4069d677", description = "Apply to _send_grok + _send_llama (Qwen deferred: uses _dashscope_call, not send_openai_compatible)" }
t1_7 = { status = "pending", commit_sha = "", description = "Apply to _send_anthropic + _send_gemini + _send_gemini_cli + _send_deepseek (consolidate inline)" } t1_7 = { status = "completed", commit_sha = "4748d134", description = "Apply to _send_gemini_cli (via send_func + on_pre_dispatch). Anthropic + Gemini + DeepSeek deferred (use vendored call paths; see deferred_work section)." }
t1_8 = { status = "pending", commit_sha = "", description = "Add scripts/audit_no_inline_tool_loops.py" } t1_8 = { status = "in_progress", commit_sha = "", description = "Add scripts/audit_no_inline_tool_loops.py" }
t1_9 = { status = "pending", commit_sha = "", description = "Phase 1 checkpoint + git note" } t1_9 = { status = "pending", commit_sha = "", description = "Phase 1 checkpoint + git note" }
# Phase 2: PROVIDERS move # Phase 2: PROVIDERS move
t2_1 = { status = "pending", commit_sha = "", description = "Decide: src/ai_client.py vs new src/ai_client_providers.py" } t2_1 = { status = "pending", commit_sha = "", description = "Decide: src/ai_client.py vs new src/ai_client_providers.py" }
+43
View File
@@ -0,0 +1,43 @@
"""Audit: fail if any _send_<vendor> in src/ai_client.py contains an inline
tool-call loop (i.e., a for loop with MAX_TOOL_ROUNDS in it).
The follow-up track's invariant: all tool loops should go through
run_with_tool_loop. Inline loops are forbidden EXCEPT for the 4
vendored-call-path vendors (anthropic, gemini, gemini_native,
deepseek) which use their own SDKs and are tracked as deferred
work in state.toml's deferred_work section.
Usage: uv run python scripts/audit_no_inline_tool_loops.py
Exit code: 0 = pass; 1 = violations found.
"""
import re
import sys
from pathlib import Path
TARGET = Path("src/ai_client.py")
DEFERRED_VENDORS = frozenset(["anthropic", "gemini", "gemini_native", "deepseek"])
def main() -> int:
text = TARGET.read_text(encoding="utf-8")
violations: list[str] = []
for match in re.finditer(r"^def (_send_\w+)\(", text, re.MULTILINE):
func_name: str = match.group(1)
vendor = func_name[len("_send_"):]
if vendor in DEFERRED_VENDORS:
continue
func_start = match.start()
next_def = re.search(r"\n(?:def|async def) _send_\w+\(", text[func_start + 1:])
func_end = func_start + 1 + (next_def.start() if next_def else len(text) - func_start - 1)
func_body = text[func_start:func_end]
if "for _round_idx in range(MAX_TOOL_ROUNDS" in func_body or "for round_idx in range(MAX_TOOL_ROUNDS" in func_body:
if "run_with_tool_loop" not in func_body:
violations.append(vendor)
if violations:
print(f"FAIL: {len(violations)} vendor(s) have inline tool loops: {violations}")
print("Use src.ai_client.run_with_tool_loop instead.")
return 1
print("OK: all _send_<vendor> functions use run_with_tool_loop (deferred vendors excluded)")
return 0
if __name__ == "__main__":
sys.exit(main())