feat(07-03): AnthropicProvider singleton + output_config + truncation — D-03/D-07/D-12/D-13

- Delete MAX_AI_CHARS constant and _client() method from anthropic_provider.py
- Add self._client = AsyncAnthropic(...) singleton in __init__ (D-07)
- Add _truncate() with 60/40 split using self._context_chars (D-13)
- Add _CLASSIFICATION_SCHEMA and _SUGGESTIONS_SCHEMA module-level constants
- classify() and suggest_topics() pass output_config with json_schema format (D-03)
- stop_reason != "end_turn" degrades to parse_classification("") (T-07-08)
- Widen __init__ signature to (api_key, model, context_chars, base_url) (uniform ctor)
- Update ai/__init__.py to pass context_chars + base_url to AnthropicProvider
- Promote test_anthropic_structured_output + add test_anthropic_stop_reason_fallback
This commit is contained in:
curo1305
2026-06-04 19:10:05 +02:00
parent ea8df02491
commit efc177a155
3 changed files with 178 additions and 24 deletions
+5 -3
View File
@@ -19,7 +19,7 @@ from ai.provider_config import ProviderConfig, PROVIDER_DEFAULTS, SUPPORTS_JSON_
# Registry: maps provider_id → provider class
# "openai" uses OpenAIProvider (no response_format override needed — plain OpenAI)
# "anthropic" uses AnthropicProvider (native output_config, no base_url ctor arg until Plan 03)
# "anthropic" uses AnthropicProvider (native output_config, Plan 03 widened ctor accepts context_chars+base_url)
# All 8 OpenAI-compat vendors use GenericOpenAIProvider (D-16/D-17/D-18)
_REGISTRY: dict[str, type[AIProvider]] = {
"openai": OpenAIProvider,
@@ -65,11 +65,13 @@ def get_provider(config: ProviderConfig) -> AIProvider:
effective_context_chars = config.context_chars or defaults["context_chars"]
if config.provider_id == "anthropic":
# AnthropicProvider does not accept base_url until Plan 03 refactors it;
# pass only the args its current __init__ accepts.
# AnthropicProvider accepts context_chars and base_url (Plan 03 widened ctor).
# base_url is accepted for uniform factory signature but unused by the SDK.
return cls(
api_key=effective_api_key,
model=effective_model,
context_chars=effective_context_chars,
base_url=effective_base_url,
)
elif cls is GenericOpenAIProvider:
return cls(