Skip to content

v1.14.0

Choose a tag to compare

@pgrayy pgrayy released this 29 Oct 14:15
· 30 commits to main since this release
c2ba0f7

Major Features

Structured Output via Agentic Loop

Agents can now validate responses against predefined schemas using JSON Schema or Pydantic models. Validation occurs at response generation time with configurable retry behavior for non-conforming outputs.

agent = Agent()
result = agent(
    "John Smith is a 30 year-old software engineer",
    structured_output_model=PersonInfo
)

# Access the structured output from the result
person_info: PersonInfo = result.structured_output

See more in the docs for Structured Output.

Interrupting Agents

Interrupts now provide first-class support for Human-in-the-loop patterns in Strands. They can be raised in Hooks or directly in tool definitions. Related, MCP elicitation has been exposed on the MCPClient.

import json
from typing import Any

from strands import Agent, tool
from strands.hooks import BeforeToolCallEvent, HookProvider, HookRegistry

from my_project import delete_files, inspect_files

class ApprovalHook(HookProvider):
    def __init__(self, app_name: str) -> None:
        self.app_name = app_name

    def register_hooks(self, registry: HookRegistry, **kwargs: Any) -> None:
        registry.add_callback(BeforeToolCallEvent, self.approve)

    def approve(self, event: BeforeToolCallEvent) -> None:
        if event.tool_use["name"] != "delete_files":
            return

        approval = event.interrupt(f"{self.app_name}-approval", reason={"paths": event.tool_use["input"]["paths"]})
        if approval.lower() != "y":
            event.cancel_tool = "User denied permission to delete files"


agent = Agent(
    hooks=[ApprovalHook("myapp")],
    system_prompt="You delete files older than 5 days",
    tools=[delete_files, inspect_files],
)

paths = ["a/b/c.txt", "d/e/f.txt"]
result = agent(f"paths=<{paths}>")

while True:
    if result.stop_reason != "interrupt":
        break

    responses = []
    for interrupt in result.interrupts:
        if interrupt.name == "myapp-approval":
            user_input = input(f"Do you want to delete {interrupt.reason["paths"]} (y/N): ")
            responses.append({
                "interruptResponse": {
                    "interruptId": interrupt.id, 
                    "response": user_input
                }
            })

    result = agent(responses)

Managed MCP Connections

We've introduced MCP Connections via ToolProviders, an experimental interface that addresses the requirement to use context managers with MCP tools. The Agent now manages connection lifecycles automatically, enabling simpler syntax:

agent = Agent(tools=[stdio_mcp_client])
agent("do something")

While this feature is experimental, we aim to mark it as stable soon and welcome user testing of this and other new features.

Agent Config

Users can now define and create agents using configuration files or dictionaries:

{
  "model": "us.anthropic.claude-3-5-sonnet-20241022-v2:0",
  "prompt": "You are a coding assistant. Help users write, debug, and improve their code. You have access to file operations and can execute shell commands when needed.",
  "tools": ["strands_tools.file_read", "strands_tools.editor", "strands_tools.shell"]
}

All Changes

  • models - litellm - start and stop reasoning by @pgrayy in #947
  • feat: add experimental AgentConfig with comprehensive tool management by @mr-lee in #935
  • fix(telemetry): make strands agent invoke_agent span as INTERNAL spanKind by @poshinchen in #1055
  • feat: add multiagent hooks, add serialize & deserialize function to multiagent base & agent result by @JackYPCOnline in #1070
  • feat: Add Structured Output as part of the agent loop by @afarntrog in #943
  • integ tests - interrupts - remove asyncio marker by @pgrayy in #1045
  • interrupt - docstring - fix formatting by @pgrayy in #1074
  • ci: add pr size labeler by @dbschmigelski in #1082
  • fix: Don't bail out if there are no tool_uses by @zastrowm in #1087
  • feat(mcp): add experimental agent managed connection via ToolProvider by @dbschmigelski in #895
  • fix (bug): retry on varying Bedrock throttlingexception cases by @mehtarac in #1096
  • feat: skip model invocation when latest message contains ToolUse by @Unshure in #1068
  • direct tool call - interrupt not allowed by @pgrayy in #1097
  • mcp elicitation by @pgrayy in #1094
  • fix(litellm): enhance structured output handling by @Arindam200 in #1021
  • Transform invalid tool usages on sending, not on initial detection by @zastrowm in #1091

New Contributors

Full Changelog: v1.13.0...v1.14.0