Skip to content

Commit 5470b11

Browse files
author
Vamil Gandhi
committed
feat: add optional outputSchema support for tool specifications
- Add outputSchema as optional field in ToolSpec using NotRequired[JSONSchema] - Filter outputSchema unconditionally in streaming.py for compatibility - Add TODO comment referencing issue #780 for future improvements This allows tools to define their output schema while maintaining full backward compatibility. The outputSchema field is filtered out before sending to model providers to prevent validation errors until proper model-specific behavior handling is implemented. Closes #787
1 parent 8cb53d3 commit 5470b11

File tree

2 files changed

+17
-3
lines changed

2 files changed

+17
-3
lines changed

src/strands/event_loop/streaming.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import json
44
import logging
5-
from typing import Any, AsyncGenerator, AsyncIterable, Optional
5+
from typing import Any, AsyncGenerator, AsyncIterable, Optional, cast
66

77
from ..models.model import Model
88
from ..types._events import (
@@ -337,7 +337,17 @@ async def stream_messages(
337337
logger.debug("model=<%s> | streaming messages", model)
338338

339339
messages = remove_blank_messages_content_text(messages)
340-
chunks = model.stream(messages, tool_specs if tool_specs else None, system_prompt)
340+
341+
# TODO(#780): Remove outputSchema filtering once model-specific behavior handling is implemented.
342+
# For now, we filter out outputSchema from all tool specs to ensure compatibility with all model providers.
343+
# Some providers (e.g., Bedrock) will throw validation errors if they receive unknown fields.
344+
filtered_tool_specs = None
345+
if tool_specs:
346+
filtered_tool_specs = cast(
347+
list[ToolSpec], [{k: v for k, v in spec.items() if k != "outputSchema"} for spec in tool_specs]
348+
)
349+
350+
chunks = model.stream(messages, filtered_tool_specs, system_prompt)
341351

342352
async for event in process_stream(chunks):
343353
yield event

src/strands/types/tools.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from dataclasses import dataclass
1010
from typing import TYPE_CHECKING, Any, AsyncGenerator, Awaitable, Callable, Literal, Protocol, Union
1111

12-
from typing_extensions import TypedDict
12+
from typing_extensions import NotRequired, TypedDict
1313

1414
from .media import DocumentContent, ImageContent
1515

@@ -27,11 +27,15 @@ class ToolSpec(TypedDict):
2727
description: A human-readable description of what the tool does.
2828
inputSchema: JSON Schema defining the expected input parameters.
2929
name: The unique name of the tool.
30+
outputSchema: Optional JSON Schema defining the expected output format.
31+
Note: Not all model providers support this field. Providers that don't
32+
support it should filter it out before sending to their API.
3033
"""
3134

3235
description: str
3336
inputSchema: JSONSchema
3437
name: str
38+
outputSchema: NotRequired[JSONSchema]
3539

3640

3741
class Tool(TypedDict):

0 commit comments

Comments
 (0)