Strands Agents Integration

Strands Agents Integration#

Dogwood policies should usually guard Strands tool calls through interventions. Plugins and direct hooks are still available for lower-level integration. All three use BeforeToolCallEvent semantics: Dogwood authorizes the selected tool before Strands invokes it.

Install the optional Strands dependency:

pip install "dogwood-py[strands]"

Intervention handler#

Use DogwoodIntervention when you want Strands’ typed control flow. It returns Proceed for allowed tool calls, Deny for hard denials, and can return Confirm for human step-up approval.

from strands import Agent
from dogwood.integrations.strands import DogwoodIntervention

dogwood_policy = DogwoodIntervention(
    policy_source=policy_source,
    policy_schema_source=cedar_schema_source,
    event_schema_source=event_schema_source,
)

agent = Agent(
    tools=[search_tool, write_file],
    interventions=[dogwood_policy],
)

Structural checks that should happen before Dogwood policy evaluation belong in agent code as a separate intervention before DogwoodIntervention. This is where you can normalize model-generated tool input with transform(...) or give the model corrective feedback with guide(...).

from strands.interventions import InterventionHandler
from dogwood.integrations.strands import DogwoodIntervention, guide, proceed

class ToolInputPrecheck(InterventionHandler):
    name = "tool-input-precheck"

    def before_tool_call(self, event, **kwargs):
        tool_input = event.tool_use["input"]
        if event.tool_use["name"] == "send_email" and not tool_input.get("subject"):
            return guide("All emails must include a subject line.")
        return proceed()

dogwood_policy = DogwoodIntervention(
    policy_source=policy_source,
    policy_schema_source=cedar_schema_source,
    event_schema_source=event_schema_source,
)

agent = Agent(
    tools=[send_email],
    interventions=[ToolInputPrecheck(), dogwood_policy],
)

For step-up approval, pass confirm_when. It can be True, a prompt string, or a function that returns False, True, or a custom prompt.

high_risk_policy = DogwoodIntervention(
    policy_source=item_risk_policy,
    policy_schema_source=cedar_schema_source,
    event_schema_source=event_schema_source,
    confirm_when=lambda event: (
        "Approve this high-risk item?"
        if event.tool_use["name"] == "add_to_cart"
        else False
    ),
)

Plugin#

Use DogwoodPlugin when you want Strands to discover and register decorated plugin hooks automatically.

from strands import Agent
from dogwood.integrations.strands import DogwoodPlugin

agent = Agent(
    tools=[search_tool, write_file],
    plugins=[
        DogwoodPlugin(
            policy_source=policy_source,
            policy_schema_source=cedar_schema_source,
            event_schema_source=event_schema_source,
        )
    ],
)

Direct hook#

Use before_tool_call_hook if you need the lower-level hook object directly. Denied calls set event.cancel_tool.

from strands import Agent
from dogwood.integrations.strands import before_tool_call_hook

agent = Agent(
    tools=[search_tool, write_file],
    hooks=[
        before_tool_call_hook(
            policy_source=policy_source,
            policy_schema_source=cedar_schema_source,
            event_schema_source=event_schema_source,
        )
    ],
)

The default hook maps a Strands tool call into Dogwood input like this:

{
    "tool": event.tool_use["name"],
    "input": event.tool_use["input"],
    "toolUseId": event.tool_use.get("toolUseId", ""),
}

The default request action is Drupe::Action::CallTool. The Dogwood policy source still refers to the Cedar action as Drupe::Action::"CallTool". The principal and resource can be supplied through Strands invocation_state:

agent(
    "research Dogwood policy examples",
    principal='Drupe::OAuthUser::"alice"',
    resource='Drupe::Gateway::"agent"',
)

For framework-specific semantics, pass custom principal, resource, or input_mapper callbacks when constructing the hook.

Example#

See Strands Shopping Agent for the runnable shopping-agent example. It uses framework-neutral policies from examples/shopping_agent_policies and Strands-specific wiring from examples/strands_shopping_agent.