Skip to content

Remove default pruneMessages call from Think to preserve client-side tool results#1456

Draft
mattzcarey wants to merge 2 commits intomainfrom
feat/configurable-tool-call-pruning
Draft

Remove default pruneMessages call from Think to preserve client-side tool results#1456
mattzcarey wants to merge 2 commits intomainfrom
feat/configurable-tool-call-pruning

Conversation

@mattzcarey
Copy link
Copy Markdown
Contributor

@mattzcarey mattzcarey commented May 4, 2026

Summary

Fixes #1455.

Think hardcoded pruneMessages({ toolCalls: "before-last-2-messages" }) in the inference loop, which silently stripped client-side tool results (no execute, output supplied via addToolOutput) from any turn beyond the second. The user's choices live in those tool results, so the conversation effectively lost its memory.

This PR drops the pruneMessages call from Think._runInferenceLoop entirely. truncateOlderMessages still runs (size-trimming tool outputs >500 chars and text >10k chars in messages older than the last 4), so context cost stays bounded.

What if you want the old behavior?

Apply pruneMessages yourself in beforeTurn:

import { pruneMessages } from "ai";

beforeTurn(ctx: TurnContext) {
  return {
    messages: pruneMessages({
      messages: ctx.messages,
      toolCalls: "before-last-2-messages"
    })
  };
}

Or scope it per-tool with the array form so client-side tool results survive across turns:

beforeTurn(ctx: TurnContext) {
  return {
    messages: pruneMessages({
      messages: ctx.messages,
      toolCalls: [
        { type: "before-last-2-messages", tools: ["read_file", "search"] }
      ]
    })
  };
}

Both snippets are added to docs/think/lifecycle-hooks.md next to the existing beforeTurn examples.

Behavior change

This is a behavior change — the changeset is marked minor and explains the diff. Existing agents that benefit from the previous aggressive pruning will see longer model contexts; the size cap from truncateOlderMessages keeps the increase bounded.

Test plan

  • npm run typecheck — all 80 projects pass
  • npm run check:exports — all 8 packages valid
  • npx sherif — no issues
  • oxfmt --check . — clean
  • oxlint examples/ packages/ guides/ openai-sdk/ site/ — 0 warnings, 0 errors
  • New regression test in packages/think/src/tests/think-session.test.ts confirms client-side tool outputs (user-choice-0/1/2) all reach the model after follow-up turns
  • Full think test suite passes (290/290)
  • Manual verification by the issue reporter against their client-side-tool flow

The hardcoded pruneMessages({ toolCalls: "before-last-2-messages" }) call
silently strips client-side tool results from a 5-message conversation,
breaking multi-turn flows where the user's choices live in those tool
results (issue #1455). Add an overridable getPruneOptions() method that
returns the prune options, or null to skip pruning entirely. Default
behavior is unchanged.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 4, 2026

🦋 Changeset detected

Latest commit: 2aaf22b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@cloudflare/think Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@threepointone
Copy link
Copy Markdown
Contributor

Feels like we need a better fix than making this configurable now when we'll likely remove it later?

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

@mattzcarey
Copy link
Copy Markdown
Contributor Author

Feels like we need a better fix than making this configurable now when we'll likely remove it later?

id would prefer to remove it cause it bit me before. @threepointone I cant see it being a good default.

@mattzcarey mattzcarey marked this pull request as draft May 4, 2026 09:05
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 4, 2026

Open in StackBlitz

agents

npm i https://pkg.pr.new/agents@1456

@cloudflare/ai-chat

npm i https://pkg.pr.new/@cloudflare/ai-chat@1456

@cloudflare/codemode

npm i https://pkg.pr.new/@cloudflare/codemode@1456

hono-agents

npm i https://pkg.pr.new/hono-agents@1456

@cloudflare/shell

npm i https://pkg.pr.new/@cloudflare/shell@1456

@cloudflare/think

npm i https://pkg.pr.new/@cloudflare/think@1456

@cloudflare/voice

npm i https://pkg.pr.new/@cloudflare/voice@1456

@cloudflare/worker-bundler

npm i https://pkg.pr.new/@cloudflare/worker-bundler@1456

commit: 2aaf22b

Per #1455 and review feedback: the hardcoded
pruneMessages({ toolCalls: "before-last-2-messages" }) silently dropped
client-side tool results across turns. Rather than add a configurable
escape hatch we'll likely remove later, just stop pruning by default.

truncateOlderMessages still runs, so context cost stays bounded. Agents
that want aggressive pruning can opt in from beforeTurn — documented
with a code snippet alongside the existing examples.
@mattzcarey mattzcarey changed the title feat(think): make pruneMessages configurable via getPruneOptions fix(think): remove default pruneMessages call to preserve client-side tool results May 4, 2026
@mattzcarey
Copy link
Copy Markdown
Contributor Author

Pivoted per your feedback — dropped the default pruneMessages call entirely instead of making it configurable. truncateOlderMessages still runs so context cost stays bounded, and the beforeTurn docs now include opt-in pruning snippets for users who want the old behavior. Force-push avoided; updated PR description and changeset accordingly.

@mattzcarey mattzcarey changed the title fix(think): remove default pruneMessages call to preserve client-side tool results Remove default pruneMessages call from Think to preserve client-side tool results May 4, 2026
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.

Think: pruneMessages is too agressive "before-last-2-messages", breaks client-side tool workflows

2 participants