Skip to content

Commit d135ca5

Browse files
committed
remove litellm and openai changes for now
1 parent e9fe30b commit d135ca5

File tree

6 files changed

+12
-234
lines changed

6 files changed

+12
-234
lines changed

src/strands/models/bedrock.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ def _format_request(
222222
UserWarning,
223223
stacklevel=3
224224
)
225-
system_blocks.append({"cachePoint": {"type": self.config["cache_prompt"]}}) # only default is valid here
225+
system_blocks.append({"cachePoint": {"type": self.config["cache_prompt"]}})
226226

227227
return {
228228
"modelId": self.config["model_id"],

src/strands/models/litellm.py

Lines changed: 2 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from typing_extensions import Unpack, override
1515

1616
from ..tools import convert_pydantic_to_tool_spec
17-
from ..types.content import ContentBlock, Messages, SystemContentBlock
17+
from ..types.content import ContentBlock, Messages
1818
from ..types.exceptions import ContextWindowOverflowException
1919
from ..types.streaming import StreamEvent
2020
from ..types.tools import ToolChoice, ToolSpec
@@ -131,119 +131,6 @@ def _stream_switch_content(self, data_type: str, prev_data_type: str | None) ->
131131

132132
return chunks, data_type
133133

134-
@override
135-
@classmethod
136-
def format_request_messages(
137-
cls,
138-
messages: Messages,
139-
system_prompt: Optional[str] = None,
140-
*,
141-
system_prompt_content: Optional[list[SystemContentBlock]] = None,
142-
**kwargs: Any,
143-
) -> list[dict[str, Any]]:
144-
"""Format a LiteLLM compatible messages array with cache point support.
145-
146-
Args:
147-
messages: List of message objects to be processed by the model.
148-
system_prompt: System prompt to provide context to the model (for legacy compatibility).
149-
system_prompt_content: System prompt content blocks to provide context to the model.
150-
**kwargs: Additional keyword arguments for future extensibility.
151-
152-
Returns:
153-
A LiteLLM compatible messages array.
154-
"""
155-
formatted_messages: list[dict[str, Any]] = []
156-
157-
# Handle system prompt content blocks (preferred) or fallback to system_prompt
158-
if system_prompt_content:
159-
# For LiteLLM with Bedrock, we can support cache points
160-
system_content = []
161-
162-
for block in system_prompt_content:
163-
if "text" in block:
164-
system_content.append({"type": "text", "text": block["text"]})
165-
elif "cachePoint" in block and block["cachePoint"].get("type") == "default":
166-
# Apply cache control to the immediately preceding content block
167-
# for LiteLLM/Anthropic compatibility
168-
if system_content:
169-
system_content[-1]["cache_control"] = {"type": "ephemeral"}
170-
171-
# Create single system message with content array
172-
if system_content:
173-
formatted_messages.append({"role": "system", "content": system_content})
174-
elif system_prompt:
175-
# Fallback to simple string system prompt for legacy compatibility
176-
formatted_messages.append({"role": "system", "content": system_prompt})
177-
178-
# Process regular messages
179-
for message in messages:
180-
contents = message["content"]
181-
182-
formatted_contents = [
183-
cls.format_request_message_content(content)
184-
for content in contents
185-
if not any(block_type in content for block_type in ["toolResult", "toolUse"])
186-
]
187-
formatted_tool_calls = [
188-
cls.format_request_message_tool_call(content["toolUse"]) for content in contents if "toolUse" in content
189-
]
190-
formatted_tool_messages = [
191-
cls.format_request_tool_message(content["toolResult"])
192-
for content in contents
193-
if "toolResult" in content
194-
]
195-
196-
formatted_message = {
197-
"role": message["role"],
198-
"content": formatted_contents,
199-
**({"tool_calls": formatted_tool_calls} if formatted_tool_calls else {}),
200-
}
201-
formatted_messages.append(formatted_message)
202-
formatted_messages.extend(formatted_tool_messages)
203-
204-
return [message for message in formatted_messages if message["content"] or "tool_calls" in message]
205-
206-
@override
207-
def format_chunk(self, event: dict[str, Any]) -> StreamEvent:
208-
"""Format a LiteLLM response event into a standardized message chunk.
209-
210-
Args:
211-
event: A response event from the LiteLLM model.
212-
213-
Returns:
214-
The formatted chunk.
215-
216-
Raises:
217-
RuntimeError: If chunk_type is not recognized.
218-
"""
219-
# Handle metadata case with prompt caching support
220-
if event["chunk_type"] == "metadata":
221-
usage_data = {
222-
"inputTokens": event["data"].prompt_tokens,
223-
"outputTokens": event["data"].completion_tokens,
224-
"totalTokens": event["data"].total_tokens,
225-
}
226-
227-
# Add prompt caching support for LiteLLM
228-
if hasattr(event["data"], "prompt_tokens_details") and event["data"].prompt_tokens_details:
229-
if hasattr(event["data"].prompt_tokens_details, "cached_tokens"):
230-
usage_data["cacheReadInputTokens"] = event["data"].prompt_tokens_details.cached_tokens
231-
232-
if hasattr(event["data"], "cache_creation_input_tokens") and event["data"].cache_creation_input_tokens:
233-
usage_data["cacheWriteInputTokens"] = event["data"].cache_creation_input_tokens
234-
235-
return {
236-
"metadata": {
237-
"usage": usage_data,
238-
"metrics": {
239-
"latencyMs": 0, # TODO
240-
},
241-
},
242-
}
243-
244-
# For all other cases, use the parent implementation
245-
return super().format_chunk(event)
246-
247134
@override
248135
async def stream(
249136
self,
@@ -252,7 +139,6 @@ async def stream(
252139
system_prompt: Optional[str] = None,
253140
*,
254141
tool_choice: ToolChoice | None = None,
255-
system_prompt_content: Optional[list[SystemContentBlock]] = None,
256142
**kwargs: Any,
257143
) -> AsyncGenerator[StreamEvent, None]:
258144
"""Stream conversation with the LiteLLM model.
@@ -268,7 +154,7 @@ async def stream(
268154
Formatted message chunks from the model.
269155
"""
270156
logger.debug("formatting request")
271-
request = self.format_request(messages, tool_specs, system_prompt_content, tool_choice)
157+
request = self.format_request(messages, tool_specs, system_prompt, tool_choice)
272158
logger.debug("request=<%s>", request)
273159

274160
logger.debug("invoking model")

src/strands/models/openai.py

Lines changed: 6 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from pydantic import BaseModel
1515
from typing_extensions import Unpack, override
1616

17-
from ..types.content import ContentBlock, Messages, SystemContentBlock
17+
from ..types.content import ContentBlock, Messages
1818
from ..types.exceptions import ContextWindowOverflowException, ModelThrottledException
1919
from ..types.streaming import StreamEvent
2020
from ..types.tools import ToolChoice, ToolResult, ToolSpec, ToolUse
@@ -198,21 +198,12 @@ def _format_request_tool_choice(cls, tool_choice: ToolChoice | None) -> dict[str
198198
return {"tool_choice": "auto"}
199199

200200
@classmethod
201-
def format_request_messages(
202-
cls,
203-
messages: Messages,
204-
system_prompt: Optional[str] = None,
205-
*,
206-
system_prompt_content: Optional[list[SystemContentBlock]] = None,
207-
**kwargs: Any,
208-
) -> list[dict[str, Any]]:
201+
def format_request_messages(cls, messages: Messages, system_prompt: Optional[str] = None) -> list[dict[str, Any]]:
209202
"""Format an OpenAI compatible messages array.
210203
211204
Args:
212205
messages: List of message objects to be processed by the model.
213206
system_prompt: System prompt to provide context to the model.
214-
system_prompt_content: Structured system prompt content blocks (for advanced use cases).
215-
**kwargs: Additional keyword arguments for future extensibility.
216207
217208
Returns:
218209
An OpenAI compatible messages array.
@@ -253,17 +244,14 @@ def format_request(
253244
tool_specs: Optional[list[ToolSpec]] = None,
254245
system_prompt: Optional[str] = None,
255246
tool_choice: ToolChoice | None = None,
256-
system_prompt_content: Optional[list[SystemContentBlock]] = None,
257247
) -> dict[str, Any]:
258248
"""Format an OpenAI compatible chat streaming request.
259249
260250
Args:
261251
messages: List of message objects to be processed by the model.
262252
tool_specs: List of tool specifications to make available to the model.
263-
system_prompt: System prompt to provide context to the model. When system_prompt_content
264-
is provided, this should contain the flattened text for legacy subclass compatibility.
253+
system_prompt: System prompt to provide context to the model.
265254
tool_choice: Selection strategy for tool invocation.
266-
system_prompt_content: Structured system prompt content blocks.
267255
268256
Returns:
269257
An OpenAI compatible chat streaming request.
@@ -272,27 +260,8 @@ def format_request(
272260
TypeError: If a message contains a content block type that cannot be converted to an OpenAI-compatible
273261
format.
274262
"""
275-
# Handle system prompt content with backwards compatibility
276-
# LEGACY COMPATIBILITY: The try/except approach is needed because:
277-
# 1. Some subclasses may override format_request_messages() with the old signature:
278-
# format_request_messages(cls, messages: Messages, system_prompt: Optional[str] = None)
279-
# 2. Calling with system_prompt_content kwarg would fail on legacy overrides
280-
# 3. This provides graceful fallback for existing subclass implementations
281-
if system_prompt_content:
282-
try:
283-
# Try new signature with system_prompt_content parameter
284-
messages_formatted = self.format_request_messages(
285-
messages, system_prompt, system_prompt_content=system_prompt_content
286-
)
287-
except TypeError:
288-
# Fallback for legacy subclass overrides that don't support system_prompt_content
289-
# Use system_prompt which should be populated for legacy compatibility
290-
messages_formatted = self.format_request_messages(messages, system_prompt)
291-
else:
292-
messages_formatted = self.format_request_messages(messages, system_prompt)
293-
294263
return {
295-
"messages": messages_formatted,
264+
"messages": self.format_request_messages(messages, system_prompt),
296265
"model": self.config["model_id"],
297266
"stream": True,
298267
"stream_options": {"include_usage": True},
@@ -391,7 +360,6 @@ async def stream(
391360
system_prompt: Optional[str] = None,
392361
*,
393362
tool_choice: ToolChoice | None = None,
394-
system_prompt_content: Optional[list[SystemContentBlock]] = None,
395363
**kwargs: Any,
396364
) -> AsyncGenerator[StreamEvent, None]:
397365
"""Stream conversation with the OpenAI model.
@@ -411,18 +379,7 @@ async def stream(
411379
ModelThrottledException: If the request is throttled by OpenAI (rate limits).
412380
"""
413381
logger.debug("formatting request")
414-
# TODO This logic si wrong
415-
# Use system_prompt_content if provided, otherwise fall back to system_prompt
416-
if system_prompt_content:
417-
# Extract text from first block if it's a simple text block
418-
if len(system_prompt_content) == 1 and "text" in system_prompt_content[0]:
419-
system_prompt_str = system_prompt_content[0]["text"]
420-
else:
421-
system_prompt_str = None # OpenAI doesn't support complex system content blocks
422-
else:
423-
system_prompt_str = system_prompt
424-
425-
request = self.format_request(messages, tool_specs, system_prompt_str)
382+
request = self.format_request(messages, tool_specs, system_prompt, tool_choice)
426383
logger.debug("formatted request=<%s>", request)
427384

428385
logger.debug("invoking model")
@@ -501,13 +458,7 @@ async def stream(
501458

502459
@override
503460
async def structured_output(
504-
self,
505-
output_model: Type[T],
506-
prompt: Messages,
507-
system_prompt: Optional[str] = None,
508-
*,
509-
system_prompt_content: Optional[list[SystemContentBlock]] = None,
510-
**kwargs: Any,
461+
self, output_model: Type[T], prompt: Messages, system_prompt: Optional[str] = None, **kwargs: Any
511462
) -> AsyncGenerator[dict[str, Union[T, Any]], None]:
512463
"""Get structured output from the model.
513464

src/strands/types/content.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
- Bedrock docs: https://docs.aws.amazon.com/bedrock/latest/APIReference/API_Types_Amazon_Bedrock_Runtime.html
77
"""
88

9-
from typing import Dict, List, Literal, Optional, Union
9+
from typing import Dict, List, Literal, Optional
1010

1111
from typing_extensions import TypedDict
1212

@@ -68,7 +68,7 @@ class CachePoint(TypedDict):
6868
type: The type of cache point, typically "default".
6969
"""
7070

71-
type: str # Can we change this to default without breaking
71+
type: str
7272

7373

7474
class ContentBlock(TypedDict, total=False):
@@ -103,12 +103,10 @@ class SystemContentBlock(TypedDict, total=False):
103103
"""Contains configurations for instructions to provide the model for how to handle input.
104104
105105
Attributes:
106-
cachePoint: A cache point configuration to optimize conversation history.
107106
guardContent: A content block to assess with the guardrail.
108107
text: A system prompt for the model.
109108
"""
110109

111-
cachePoint: CachePoint
112110
guardContent: GuardContent
113111
text: str
114112

tests/strands/agent/test_agent.py

Lines changed: 1 addition & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1795,7 +1795,6 @@ def test_agent_tool_record_direct_tool_call_disabled_with_non_serializable(agent
17951795
assert len(agent.messages) == 0
17961796

17971797

1798-
# TODO: dedup
17991798
def test_agent_empty_invoke():
18001799
model = MockedModelProvider([{"role": "assistant", "content": [{"text": "hello!"}]}])
18011800
agent = Agent(model=model, messages=[{"role": "user", "content": [{"text": "hello!"}]}])
@@ -2211,7 +2210,7 @@ def test_agent_none_system_prompt():
22112210
agent = Agent(system_prompt=None)
22122211

22132212
assert agent.system_prompt is None
2214-
assert agent._system_prompt_content == None
2213+
assert agent._system_prompt_content is None
22152214

22162215

22172216
def test_agent_empty_list_system_prompt():
@@ -2228,7 +2227,6 @@ def test_agent_backwards_compatibility_string_access():
22282227
agent = Agent(system_prompt=system_prompt)
22292228

22302229
# Should be able to access as string for backwards compatibility
2231-
assert isinstance(agent.system_prompt, str)
22322230
assert agent.system_prompt == system_prompt
22332231

22342232

@@ -2239,60 +2237,7 @@ def test_agent_backwards_compatibility_single_text_block():
22392237
agent = Agent(system_prompt=system_prompt_content)
22402238

22412239
# Should extract text for backwards compatibility
2242-
assert isinstance(agent.system_prompt, str)
22432240
assert agent.system_prompt == text
22442241

22452242

2246-
def test_agent_initialize_system_prompt_string_input():
2247-
"""Test _initialize_system_prompt with string input."""
2248-
agent = Agent()
2249-
result = agent._initialize_system_prompt("Test prompt")
2250-
2251-
assert result == ("Test prompt", [{"text": "Test prompt"}])
2252-
2253-
2254-
def test_agent_initialize_system_prompt_single_text_block_input():
2255-
"""Test _initialize_system_prompt with single text block."""
2256-
agent = Agent()
2257-
input_blocks = [{"text": "Test prompt"}]
2258-
result = agent._initialize_system_prompt(input_blocks)
2259-
2260-
assert result == ("Test prompt", input_blocks)
2261-
2262-
2263-
def test_agent_initialize_system_prompt_multiple_blocks_input():
2264-
"""Test _initialize_system_prompt with multiple blocks."""
2265-
agent = Agent()
2266-
input_blocks = [
2267-
{"text": "First block"},
2268-
{"cachePoint": {"type": "default"}},
2269-
{"text": "Second block"}
2270-
]
2271-
result = agent._initialize_system_prompt(input_blocks)
2272-
2273-
assert result == ("First block\nSecond block", input_blocks)
22742243

2275-
2276-
def test_agent_initialize_system_prompt_single_non_text_block_input():
2277-
"""Test _initialize_system_prompt with single non-text block."""
2278-
agent = Agent()
2279-
input_blocks = [{"cachePoint": {"type": "default"}}]
2280-
result = agent._initialize_system_prompt(input_blocks)
2281-
2282-
assert result == (None, input_blocks)
2283-
2284-
2285-
def test_agent_initialize_system_prompt_none_input():
2286-
"""Test _initialize_system_prompt with None input."""
2287-
agent = Agent()
2288-
result = agent._initialize_system_prompt(None)
2289-
2290-
assert result == (None, None)
2291-
2292-
2293-
def test_agent_initialize_system_prompt_empty_list_input():
2294-
"""Test _initialize_system_prompt with empty list."""
2295-
agent = Agent()
2296-
result = agent._initialize_system_prompt([])
2297-
2298-
assert result == (None, [])

0 commit comments

Comments
 (0)