Skip to content

fix(tools): preserve conversation history across multi-step tool calls#40

Merged
iskakaushik merged 2 commits intomainfrom
fix/multi-step-coordinator
May 1, 2026
Merged

fix(tools): preserve conversation history across multi-step tool calls#40
iskakaushik merged 2 commits intomainfrom
fix/multi-step-coordinator

Conversation

@iskakaushik
Copy link
Copy Markdown
Collaborator

Summary

Multi-turn tool calling on this branch had two bugs that combined to make the model repeatedly re-issue the same tool calls:

  • MultiStepCoordinator::execute_multi_step rebuilt each step's input from initial_options + only the most recent step's tool calls/results, so earlier turns were lost between iterations. Refactored to mirror the Vercel AI SDK pattern (packages/ai/src/generate-text/generate-text.ts): immutable initial_messages + a response_messages accumulator; each step's input is the concatenation of the two.
  • OpenAIRequestBuilder silently dropped options.system whenever the caller supplied a non-empty messages array. The OpenAI Chat Completions API has no top-level `system` field — it must be a leading `role: "system"` message. The Anthropic builder already handled this correctly via `request["system"]`.

The two changes together also let the coordinator drop a workaround that was pushing the system prompt as a role=user message.

Validates against the existing MultiStepDuplicateExecutionTest cases (which were known-failing per issue #26). They now pass for both OpenAI and Anthropic.

Also adds `tests/cmake_test_discovery_*.json` to `.gitignore` (CMake test discovery cache, no need to track).

Test plan

  • `pnpm`-equivalent: `make ai_tests` clean build
  • `ctest -R MultiStepDuplicate` — 4/4 pass against real OpenAI + Anthropic
  • End-to-end multi-step demo (langfuse_tracing example, separate PR) produces 1 turn per tool call rather than re-issuing

Two bugs caused multi-step tool calling to repeatedly re-issue the same
tool calls and drop the system prompt:

- MultiStepCoordinator::execute_multi_step rebuilt step inputs from
  initial_options + only the most recent step's tool calls/results, so
  earlier turns were lost between iterations. Refactor to mirror the
  Vercel AI SDK pattern (packages/ai/src/generate-text/generate-text.ts):
  immutable initial_messages plus a response_messages accumulator;
  each step's input is the concatenation of the two.

- OpenAIRequestBuilder dropped options.system whenever the caller
  supplied a non-empty messages array (the Chat Completions API has no
  top-level system field; system must be a leading role=system message).
  Anthropic's builder already handled this correctly via request["system"].

Validated by the existing MultiStepDuplicateExecutionTest cases, which
were known-failing per issue #26 and now pass for both providers.
Adds tests/cmake_test_discovery_*.json to .gitignore (build artifact).
@iskakaushik iskakaushik merged commit f9d8b40 into main May 1, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant