Skip to content

feat(toolset): trigger cross-step dedup reminder only after 7 consecutive repeats#2280

Open
jackfish212 wants to merge 2 commits into
MoonshotAI:mainfrom
jackfish212:repeat-avo
Open

feat(toolset): trigger cross-step dedup reminder only after 7 consecutive repeats#2280
jackfish212 wants to merge 2 commits into
MoonshotAI:mainfrom
jackfish212:repeat-avo

Conversation

@jackfish212
Copy link
Copy Markdown
Collaborator

@jackfish212 jackfish212 commented May 14, 2026

Summary

This PR raises the threshold for triggering cross-step deduplication reminders from "any repeat" to "7 consecutive identical calls". This reduces noise from legitimate repeated tool usage while still surfacing stuck-loop behavior to the model.


1. Cross-step dedup reminder threshold

Problem: Previously, any tool call identical to one in the previous step would trigger a deduplication reminder. This was overly aggressive for workflows that legitimately need to call the same tool with the same arguments multiple times across steps (e.g., polling, incremental reads).

What was done:

  • Introduced _CROSS_STEP_DEDUP_TRIGGER_COUNT = 7 constant.
  • Added _consecutive_call_key and _consecutive_call_count to KimiToolset to track how many times the exact same (tool_name, arguments) pair has been called consecutively across steps.
  • Implemented _sync_consecutive_state_from_previous_calls() to initialize the counter from the previous step'''s call history.
  • Implemented _projected_consecutive_state() to evaluate whether the current call would hit the threshold after accounting for calls already made in the current step.
  • The dedup reminder is now only triggered when the projected consecutive count reaches 7.

2. Counter reset behavior

Problem: The consecutive counter needs to reset when a different tool or different arguments intervene, otherwise unrelated calls could inadvertently contribute to the threshold.

What was done:

  • The counter resets whenever a call with a different (tool_name, arguments) key appears.
  • This reset applies both across steps (via begin_step / end_step state tracking) and within the same step (via _projected_consecutive_state).

3. Test coverage

What was done:

  • Updated test_cross_step_duplicate_appends_reminder to verify the reminder appears on the 7th occurrence.
  • Added test_cross_step_repeat_counter_resets_after_other_tool_call to verify an intervening different tool call resets the counter.
  • Added test_cross_step_repeat_counter_resets_with_intervening_call_in_same_step to verify a different call within the same step also resets the counter.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked the related issue, if any.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have run make gen-changelog to update the changelog.
  • I have run make gen-docs to update the user documentation.

Open in Devin Review

…tive repeats

- add consecutive call counter to track repeat occurrences across steps\n- trigger cross-step dedup reminder only on 7th consecutive identical call\n- reset counter when a different tool or arguments intervene\n- update tests for new threshold and reset behavior
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 bugs or issues to report.

Open in Devin Review

@sailist
Copy link
Copy Markdown
Collaborator

sailist commented May 14, 2026

@codex

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4e5677b9c0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/kosong/src/kosong/_generate.py Outdated
Comment on lines 91 to 94
if pending_part is not None:
_message_append(message, pending_part)
if isinstance(pending_part, ToolCall) and on_tool_call:
await callback(on_tool_call, pending_part)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid duplicating tool calls when cancellation hits callback

If the task is cancelled while awaiting on_tool_call after _message_append has already appended pending_part, the except asyncio.CancelledError block re-appends the same pending_part because it is not cleared until after the callback returns. In that cancellation window (including async/custom on_tool_call callbacks), the StepCancelled partial contains duplicate assistant tool calls with the same id, and KimiSoul will persist/send duplicate paired results, leaving malformed history for the next model call.

Useful? React with 👍 / 👎.

- record interrupted tool results in context when step is cancelled\n- send ToolError with "Interrupted By User" for pending tool calls\n- add unit and e2e tests for tool interrupt scenarios\n- suppress auto-completion when browsing recalled history entries in shell UI
@sailist
Copy link
Copy Markdown
Collaborator

sailist commented May 14, 2026

@codex

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bb4dece9bd

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

async for part in stream:
logger.trace("Received part: {part}", part=part)
if on_message_part:
await callback(on_message_part, part.model_copy(deep=True))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Record streamed parts before awaiting callbacks

When on_message_part is an async callback, a user cancellation delivered while this await is in progress raises GenerateCancelled before the newly streamed part has been merged into pending_part or message. In that scenario the callback may already have rendered a text/tool-call chunk to the UI, but the partial result used to repair history omits it, so a visible tool call can still be persisted without the required synthetic tool result (or lost entirely).

Useful? React with 👍 / 👎.

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.

2 participants