vovkes222 Claude Opus 4.6 commited on
Commit
e56db6a
·
1 Parent(s): a742ce2

feat: switch to AWS Bedrock only, remove direct Anthropic/OpenAI API

Browse files

All LLM calls go through Bedrock. No direct API fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

app.py CHANGED
@@ -26,7 +26,11 @@ EXAMPLES = [
26
 
27
 
28
  def has_api_keys() -> bool:
29
- return bool(os.environ.get("ANTHROPIC_API_KEY") or os.environ.get("OPENAI_API_KEY"))
 
 
 
 
30
 
31
 
32
  async def _run_pipeline(question: str):
 
26
 
27
 
28
  def has_api_keys() -> bool:
29
+ return bool(
30
+ os.environ.get("AWS_REGION")
31
+ or os.environ.get("ANTHROPIC_API_KEY")
32
+ or os.environ.get("OPENAI_API_KEY")
33
+ )
34
 
35
 
36
  async def _run_pipeline(question: str):
requirements.txt CHANGED
@@ -2,6 +2,5 @@ gradio>=5.0
2
  pyyaml>=6.0
3
  httpx>=0.27
4
  pydantic>=2.7
5
- anthropic>=0.40
6
- openai>=1.50
7
  rich>=13.0
 
2
  pyyaml>=6.0
3
  httpx>=0.27
4
  pydantic>=2.7
5
+ anthropic[bedrock]>=0.40
 
6
  rich>=13.0
src/legal_intern/core/config.py CHANGED
@@ -15,7 +15,7 @@ class Config:
15
 
16
  # LLM provider
17
  default_provider: str = "anthropic"
18
- default_model: str = "claude-sonnet-4-6"
19
 
20
  # Per-agent model overrides
21
  model_overrides: dict[str, str] = field(default_factory=dict)
@@ -37,6 +37,11 @@ class Config:
37
  anthropic_api_key: str = ""
38
  openai_api_key: str = ""
39
 
 
 
 
 
 
40
  def model_for(self, agent_role: str) -> str:
41
  return self.model_overrides.get(agent_role, self.default_model)
42
 
@@ -56,4 +61,7 @@ class Config:
56
  config.secondlayer_api_url = os.environ.get(
57
  "SECONDLAYER_API_URL", config.secondlayer_api_url
58
  )
 
 
 
59
  return config
 
15
 
16
  # LLM provider
17
  default_provider: str = "anthropic"
18
+ default_model: str = "us.anthropic.claude-sonnet-4-6-20250514-v1:0"
19
 
20
  # Per-agent model overrides
21
  model_overrides: dict[str, str] = field(default_factory=dict)
 
37
  anthropic_api_key: str = ""
38
  openai_api_key: str = ""
39
 
40
+ # AWS Bedrock
41
+ aws_region: str = ""
42
+ aws_access_key_id: str = ""
43
+ aws_secret_access_key: str = ""
44
+
45
  def model_for(self, agent_role: str) -> str:
46
  return self.model_overrides.get(agent_role, self.default_model)
47
 
 
61
  config.secondlayer_api_url = os.environ.get(
62
  "SECONDLAYER_API_URL", config.secondlayer_api_url
63
  )
64
+ config.aws_region = os.environ.get("AWS_REGION", "")
65
+ config.aws_access_key_id = os.environ.get("AWS_ACCESS_KEY_ID", "")
66
+ config.aws_secret_access_key = os.environ.get("AWS_SECRET_ACCESS_KEY", "")
67
  return config
src/legal_intern/providers/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- """LLM provider abstraction layer."""
2
 
3
  from __future__ import annotations
4
 
@@ -31,21 +31,12 @@ async def call_llm(
31
  json_mode: bool = False,
32
  tools: list[dict] | None = None,
33
  ) -> LLMResponse:
34
- """Call the LLM provider configured for this agent role.
35
-
36
- Each agent call starts from a fresh context -- no conversation history.
37
- """
38
  model = config.model_for(model_key)
39
-
40
- if config.default_provider == "anthropic" or model.startswith("claude"):
41
- return await _call_anthropic(config, system, user, model, json_mode, tools)
42
- elif config.default_provider == "openai" or model.startswith("gpt"):
43
- return await _call_openai(config, system, user, model, json_mode, tools)
44
- else:
45
- raise ValueError(f"Unknown provider: {config.default_provider}")
46
 
47
 
48
- async def _call_anthropic(
49
  config: Config,
50
  system: str,
51
  user: str,
@@ -55,7 +46,11 @@ async def _call_anthropic(
55
  ) -> LLMResponse:
56
  import anthropic
57
 
58
- client = anthropic.AsyncAnthropic(api_key=config.anthropic_api_key)
 
 
 
 
59
 
60
  kwargs: dict[str, Any] = {
61
  "model": model,
@@ -77,7 +72,6 @@ async def _call_anthropic(
77
  parsed = None
78
  if json_mode:
79
  try:
80
- # Try to extract JSON from the response
81
  text = content.strip()
82
  if text.startswith("```"):
83
  text = text.split("```")[1]
@@ -95,47 +89,3 @@ async def _call_anthropic(
95
  tokens_used=tokens,
96
  parsed_json=parsed,
97
  )
98
-
99
-
100
- async def _call_openai(
101
- config: Config,
102
- system: str,
103
- user: str,
104
- model: str,
105
- json_mode: bool,
106
- tools: list[dict] | None,
107
- ) -> LLMResponse:
108
- from openai import AsyncOpenAI
109
-
110
- client = AsyncOpenAI(api_key=config.openai_api_key)
111
-
112
- kwargs: dict[str, Any] = {
113
- "model": model,
114
- "messages": [
115
- {"role": "system", "content": system},
116
- {"role": "user", "content": user},
117
- ],
118
- "max_tokens": 8192,
119
- }
120
-
121
- if json_mode:
122
- kwargs["response_format"] = {"type": "json_object"}
123
-
124
- response = await client.chat.completions.create(**kwargs)
125
-
126
- content = response.choices[0].message.content or ""
127
-
128
- parsed = None
129
- if json_mode:
130
- try:
131
- parsed = json.loads(content)
132
- except json.JSONDecodeError:
133
- parsed = None
134
-
135
- tokens = (response.usage.prompt_tokens + response.usage.completion_tokens) if response.usage else 0
136
-
137
- return LLMResponse(
138
- content=content,
139
- tokens_used=tokens,
140
- parsed_json=parsed,
141
- )
 
1
+ """LLM provider abstraction layer -- AWS Bedrock only."""
2
 
3
  from __future__ import annotations
4
 
 
31
  json_mode: bool = False,
32
  tools: list[dict] | None = None,
33
  ) -> LLMResponse:
34
+ """Call Anthropic via AWS Bedrock. No direct API calls."""
 
 
 
35
  model = config.model_for(model_key)
36
+ return await _call_bedrock(config, system, user, model, json_mode, tools)
 
 
 
 
 
 
37
 
38
 
39
+ async def _call_bedrock(
40
  config: Config,
41
  system: str,
42
  user: str,
 
46
  ) -> LLMResponse:
47
  import anthropic
48
 
49
+ client = anthropic.AsyncAnthropicBedrock(
50
+ aws_region=config.aws_region,
51
+ aws_access_key=config.aws_access_key_id or None,
52
+ aws_secret_key=config.aws_secret_access_key or None,
53
+ )
54
 
55
  kwargs: dict[str, Any] = {
56
  "model": model,
 
72
  parsed = None
73
  if json_mode:
74
  try:
 
75
  text = content.strip()
76
  if text.startswith("```"):
77
  text = text.split("```")[1]
 
89
  tokens_used=tokens,
90
  parsed_json=parsed,
91
  )