#80

DeepSeek tool calling error in PentestAgent

OpenEasonc8opened 4mo ago

Bug: DeepSeek tool calling error in PentestAgent

Description

When using PentestAgent with DeepSeek through LiteLLM, tool execution sometimes fails with the following error:

LLM Error: litellm.BadRequestError: DeepseekException - {"error":{"message":"Messages with role 'tool' must be a response to a preceding message with 'tool_calls'","type":"invalid_request_error","param":null,"code":"invalid_request_error"}}

It looks like PentestAgent may be sending a role: tool message back to DeepSeek without the required immediately preceding assistant message containing tool_calls.

According to DeepSeek's tool calling flow, the assistant response should contain tool_calls, then the client executes the tool, and then appends a role: tool message with the matching tool_call_id.

Environment

  • OS: Windows
  • Shell: PowerShell
  • Python version: 3.10.10
  • PentestAgent version: last
  • LiteLLM version: last

Model configuration

My .env uses DeepSeek.

DEEPSEEK_API_KEY=<xxx>
PENTESTAGENT_MODEL=deepseek/deepseek-v4-pro
PENTESTAGENT_EMBEDDINGS=local
PENTESTAGENT_DEBUG=false

I also tried / plan to try:

PENTESTAGENT_MODEL=deepseek/deepseek-v4-flash

Steps to reproduce

  1. Install PentestAgent on Windows.
  2. Configure .env with DeepSeek API key and model.
  3. Start PentestAgent:
python -m pentestagent
  1. Run an interactive or assist task that causes tool execution.
  2. After a terminal/tool result is produced, the LLM call fails with the DeepSeek error above.

Example tool output before the error:

terminal
{'command': 'type loot\\artifacts\\member_cp.html', 'timeout': 10}

Then PentestAgent reports:

Messages with role 'tool' must be a response to a preceding message with 'tool_calls'

Expected behavior

PentestAgent should preserve the correct tool calling message sequence when using DeepSeek through LiteLLM:

  1. Assistant message with tool_calls
  2. Tool execution
  3. Tool result message with matching tool_call_id
  4. Continue the model response

Actual behavior

DeepSeek rejects the request because a role: tool message appears without a valid preceding assistant message containing tool_calls.

Activity

1
swf19961208d ago

Found while testing LLM provider integrations in agent frameworks: an automated tool flags candidates and each one is reproduced before it is reported. Reproduced on 8dde193 against a local endpoint, so this shows the request shape and no call to DeepSeek was made.

This looks like conversation summarization. get_messages_with_summary splits the history at a fixed index, so with parallel tool calls the kept window can start on a tool message whose assistant tool_calls turn went into the summary. With six turns of two parallel calls each and a large tool output, a 90k token history (threshold 61,440) went out like this:

roles sent: ['system', 'system', 'tool', 'assistant', 'tool', 'tool', 'assistant', ...]
first kept message: tool call_2_b
tool results without their tool call in the request: ['call_2_b']

That is the shape your error complains about, and it would explain why it only shows up sometimes, on long runs. I can't tell from here that it is what happened in your session, but it's easy to check: the failing request should start with a tool message right after the summary.

Fix idea: move split_point back while messages[split_point] is a tool message, and drop leading tool messages in _truncate_to_fit, which has the same boundary problem.