From d56acec1b43e38874ed50c119b81eae02437cab8 Mon Sep 17 00:00:00 2001 From: tanzhenxin Date: Wed, 10 Jun 2026 16:33:39 +0800 Subject: [PATCH] fix(core): give complete intentional-sleep guidance on first rejection for sleep chains When the model tries `sleep 5 && cmd`, the old error message said 'split follow-up commands into a separate invocation' but omitted the `# intentional-sleep: ` syntax. The model would then try standalone `sleep 5`, get blocked a second time, and only then learn the escape hatch. Now the first rejection for non-standalone sleep tells the model both steps: split into two calls and use the intentional-sleep comment. This reduces failures from 2 to 1. Also reuses the already-computed `strippedCommand` variable instead of calling `stripShellWrapper` a second time. --- packages/core/src/tools/shell.test.ts | 9 ++++----- packages/core/src/tools/shell.ts | 6 ++---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/core/src/tools/shell.test.ts b/packages/core/src/tools/shell.test.ts index 25a6e952897..8a0a9bcf321 100644 --- a/packages/core/src/tools/shell.test.ts +++ b/packages/core/src/tools/shell.test.ts @@ -195,16 +195,15 @@ describe('ShellTool', () => { expect(error).toBeNull(); }); - it('should not suggest the intentional sleep comment for sleep chains', async () => { + it('should guide model to split and use intentional-sleep for sleep chains', async () => { const error = shellTool.validateToolParams({ command: 'sleep 5 && echo ok', is_background: false, }); - expect(error).toContain( - 'intentional-sleep escape hatch only applies to standalone sleep commands', - ); - expect(error).not.toContain('# intentional-sleep:'); + expect(error).toContain('Split into two calls'); + expect(error).toContain('intentional-sleep:'); + expect(error).toContain('reason'); }); it('should throw an error for a relative directory path', async () => { diff --git a/packages/core/src/tools/shell.ts b/packages/core/src/tools/shell.ts index be3944f27f9..621d16dec38 100644 --- a/packages/core/src/tools/shell.ts +++ b/packages/core/src/tools/shell.ts @@ -4361,16 +4361,14 @@ export class ShellTool extends BaseDeclarativeTool< // `-c` script. This matches every other sensitive check in this file // (directory, read-only, command-root extraction, etc.). if (!params.is_background) { - const sleepPattern = detectBlockedSleepPatternDetails( - stripShellWrapper(params.command), - ); + const sleepPattern = detectBlockedSleepPatternDetails(strippedCommand); if (sleepPattern !== null) { const intentionalSleepGuidance = sleepPattern.intentionalSleepRejection ?? (sleepPattern.isStandalone ? 'If you genuinely need a standalone delay (rate limiting, deliberate pacing), ' + 'add a trailing comment like `# intentional-sleep: wait for MCP rate limit reset` (up to 10 minutes).' - : 'The intentional-sleep escape hatch only applies to standalone sleep commands; split follow-up commands into a separate invocation.'); + : 'Split into two calls: first `sleep N # intentional-sleep: ` (standalone), then the follow-up command.'); return ( `Blocked: ${sleepPattern.description}. ` + 'Run blocking commands in the background with is_background: true. ' +