Skip to content

[BUG] SlidingWindowConversationManager can emit assistant-first function call history causing Gemini 400 INVALID_ARGUMENT #1749

@KKamJi98

Description

@KKamJi98

Checks

  • I have updated to the lastest minor and patch version of Strands
  • I have checked the documentation and this is not expected behavior
  • I have searched ./issues and there are no duplicates of my issue

Strands Version

1.23.0

Python Version

3.12.12

Operating System

Ubuntu 24.04 LTS 6.8.0-94-generic

Installation Method

Docker + uv (uv pip install --system .)

Steps to Reproduce

  1. Use SlidingWindowConversationManager(window_size=40) in a long multi-turn chat with tool calls.
  2. Let history reach context reduction path where latest toolResult was already replaced with:
    • status: "error"
    • content: [{"text": "The tool result was too large!"}]
  3. reduce_context() calls _truncate_tool_results() once on the latest toolResult message.
  4. _truncate_tool_results() returns False immediately when it sees that already-truncated toolResult.
  5. reduce_context() falls through to window trimming.
  6. Trim result can start with an assistant toolUse turn.
  7. Send that history to Gemini model.

Minimal sequence shape that can be produced after trimming:

[
  {"role":"assistant","content":[{"toolUse":{"toolUseId":"a1","name":"get_pod_status","input":{}}}]},
  {"role":"user","content":[{"toolResult":{"toolUseId":"a1","status":"success","content":[{"text":"..."}]}}]}
]

Expected Behavior

  • Context reduction should continue searching for another truncatable toolResult when latest one is already truncated.
  • Reduced history should not start with assistant toolUse (function call) turn.
  • Gemini requests should avoid 400 invalid turn-order errors caused by conversation reduction.

Actual Behavior

  • _truncate_tool_results() short-circuits on already-truncated latest result, so no other candidates are attempted.
  • Window trimming may leave assistant function-call turn as the first message.
  • Gemini returns 400 INVALID_ARGUMENT with message similar to:
Please ensure that function call turn comes immediately after a user turn or after a function response turn.

Additional Context

  • Related logging before failure frequently includes:
    • ToolResult has already been updated, skipping overwrite
  • This appears to be a combination of two issues:
    1. Early return in _truncate_tool_results() on already-truncated result.
    2. No post-trim guard against assistant toolUse at history start.

Possible Solution

  1. In reduce_context(), scan older messages for truncation candidates when latest candidate cannot be truncated.
  2. In _truncate_tool_results(), skip already-truncated entries (continue) instead of aborting.
  3. After trimming/truncation, sanitize leading assistant toolUse turns so reduced history does not start with a function call.

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions