Coverage for src / infra / clients / anthropic_client.py: 14%

21 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2026-01-04 04:43 +0000

1"""Shared Anthropic client factory for mala orchestrator. 

2 

3This module provides a centralized way to create Anthropic clients with: 

4- Consistent configuration from MalaConfig (api_key, base_url) 

5- Automatic Braintrust wrapping for observability when available 

6 

7Usage: 

8 from src.infra.clients.anthropic_client import create_anthropic_client 

9 from src.infra.io.config import MalaConfig 

10 

11 config = MalaConfig.from_env() 

12 client = create_anthropic_client( 

13 api_key=config.llm_api_key, 

14 base_url=config.llm_base_url, 

15 timeout=120.0, 

16 ) 

17 

18 # Client is ready to use with Braintrust tracing enabled (if configured) 

19 response = client.messages.create( 

20 model="claude-sonnet-4-20250514", 

21 max_tokens=1024, 

22 messages=[{"role": "user", "content": "Hello"}], 

23 ) 

24""" 

25 

26from __future__ import annotations 

27 

28from typing import Any 

29 

30 

31def create_anthropic_client( 

32 *, 

33 api_key: str | None = None, 

34 base_url: str | None = None, 

35 timeout: float | None = None, 

36) -> Any: # noqa: ANN401 - Return type is dynamic (Anthropic or wrapped client) 

37 """Create an Anthropic client with consistent configuration and tracing. 

38 

39 This factory function centralizes Anthropic client creation to ensure: 

40 1. Configuration is applied consistently (api_key, base_url) 

41 2. Braintrust tracing is automatically enabled when available 

42 3. Error handling and telemetry work uniformly across components 

43 

44 Args: 

45 api_key: Anthropic API key. If not provided, the client will use 

46 the ANTHROPIC_API_KEY environment variable. 

47 base_url: Optional base URL for API requests. Use this to route 

48 requests through proxies. 

49 timeout: Optional timeout in seconds for API requests. 

50 

51 Returns: 

52 An Anthropic client instance, optionally wrapped with Braintrust 

53 tracing if available. 

54 

55 Raises: 

56 RuntimeError: If the anthropic package is not installed. 

57 

58 Example: 

59 from src.infra.clients.anthropic_client import create_anthropic_client 

60 

61 # Basic usage with env var for API key 

62 client = create_anthropic_client() 

63 

64 # With explicit configuration 

65 client = create_anthropic_client( 

66 api_key="sk-...", 

67 base_url="https://proxy.example.com/v1", 

68 timeout=60.0, 

69 ) 

70 

71 # Braintrust tracing is automatic when BRAINTRUST_API_KEY is set 

72 """ 

73 try: 

74 from anthropic import Anthropic # type: ignore[import-untyped] 

75 except ImportError as e: 

76 raise RuntimeError( 

77 "anthropic package is required. Install with: uv add anthropic" 

78 ) from e 

79 

80 # Build client kwargs, only including non-None values 

81 client_kwargs: dict[str, object] = {} 

82 if api_key is not None: 

83 client_kwargs["api_key"] = api_key 

84 if base_url is not None: 

85 client_kwargs["base_url"] = base_url 

86 if timeout is not None: 

87 client_kwargs["timeout"] = timeout 

88 

89 # Create the base client 

90 client = Anthropic(**client_kwargs) 

91 

92 # Wrap with Braintrust for observability (no-op if Braintrust not configured) 

93 # This provides automatic tracing of all LLM calls when BRAINTRUST_API_KEY is set 

94 try: 

95 from braintrust import wrap_anthropic 

96 

97 client = wrap_anthropic(client) 

98 except ImportError: 

99 pass # Braintrust not installed, proceed without tracing 

100 

101 return client