Compare commits

...

4 Commits

3 changed files with 51 additions and 0 deletions
+1
View File
@@ -233,6 +233,7 @@ Use the following guidelines to optimize your search and read patterns.
- **Types, warnings and linters:** NEVER use hacks like disabling or suppressing warnings or bypassing the type system (i.e.: casts in TypeScript) unless explicitly instructed to by the user. Instead, use idiomatic language features (e.g.: type guard functions).
- **Libraries/Frameworks:** NEVER assume a library/framework is available. Verify its established usage within the project (check imports, configuration files like 'package.json', 'Cargo.toml', 'requirements.txt', etc.) before employing it.
- **Technical Integrity:** You are responsible for the entire lifecycle: implementation, testing, and validation. Within the scope of your changes, prioritize readability and long-term maintainability by consolidating logic into clean abstractions rather than threading state across unrelated layers. Align strictly with the requested architectural direction, ensuring the final implementation is focused and free of redundant "just-in-case" alternatives. Validation is not merely running tests; it is the exhaustive process of ensuring that every aspect of your change—behavioral, structural, and stylistic—is correct and fully compatible with the broader project. For bug fixes, you must empirically reproduce the failure with a new test case or reproduction script before applying the fix.
- **Multi-line File Creation:** ALWAYS use the ${formatToolName(WRITE_FILE_TOOL_NAME)} tool for creating or overwriting files with multiple lines of content. DO NOT use ${formatToolName(SHELL_TOOL_NAME)} with \`cat << 'EOF'\` or similar heredoc patterns, as they are prone to shell parsing errors and internal buffer limits.
- **Expertise & Intent Alignment:** Provide proactive technical opinions grounded in research while strictly adhering to the user's intended workflow. Distinguish between **Directives** (unambiguous requests for action or implementation) and **Inquiries** (requests for analysis, advice, or observations). Assume all requests are Inquiries unless they contain an explicit instruction to perform a task. For Inquiries, your scope is strictly limited to research and analysis; you may propose a solution or strategy, but you MUST NOT modify files until a corresponding Directive is issued. Do not initiate implementation based on observations of bugs or statements of fact. Once an Inquiry is resolved, or while waiting for a Directive, stop and wait for the next user instruction. ${options.interactive ? 'For Directives, only clarify if critically underspecified; otherwise, work autonomously.' : 'For Directives, you must work autonomously as no further user input is available.'} You should only seek user intervention if you have exhausted all possible routes or if a proposed solution would take the workspace in a significantly different architectural direction.
- **Proactiveness:** When executing a Directive, persist through errors and obstacles by diagnosing failures in the execution phase and, if necessary, backtracking to the research or strategy phases to adjust your approach until a successful, verified outcome is achieved. Fulfill the user's request thoroughly, including adding tests when adding features or fixing bugs. Take reasonable liberties to fulfill broad goals while staying within the requested scope; however, prioritize simplicity and the removal of redundant logic over providing "just-in-case" alternatives that diverge from the established path.
- **Testing:** ALWAYS search for and update related tests after making a code change. You must add a new test case to the existing test file (if one exists) or create a new test file to verify your changes.${mandateConflictResolution(options.hasHierarchicalMemory)}
+32
View File
@@ -470,6 +470,38 @@ describe('ShellTool', () => {
expect(result.error?.message).toBe('command failed');
});
it('should include write_file suggestion when a command with a heredoc fails', async () => {
const invocation = shellTool.build({
command: "cat << 'EOF'\nhello\nEOF",
});
const promise = invocation.execute(mockAbortSignal);
resolveShellExecution({
exitCode: 1,
output: 'bash: syntax error',
});
const result = await promise;
expect(result.llmContent).toContain(
"Suggestion: Large heredoc detected. Please use the 'write_file' tool for better reliability.",
);
});
it('should NOT include write_file suggestion when a command with a heredoc succeeds', async () => {
const invocation = shellTool.build({
command: "cat << 'EOF'\nhello\nEOF",
});
const promise = invocation.execute(mockAbortSignal);
resolveShellExecution({
exitCode: 0,
output: 'hello',
});
const result = await promise;
expect(result.llmContent).not.toContain(
"Suggestion: Large heredoc detected. Please use the 'write_file' tool for better reliability.",
);
});
it('should throw an error for invalid parameters', () => {
expect(() => shellTool.build({ command: '' })).toThrow(
'Command cannot be empty.',
+18
View File
@@ -51,6 +51,8 @@ import type { AgentLoopContext } from '../config/agent-loop-context.js';
export const OUTPUT_UPDATE_INTERVAL_MS = 1000;
const HEREDOC_REGEX = /<<[-]?\s*['"\\\]?EOF['"]?/;
// Delay so user does not see the output of the process before the process is moved to the background.
const BACKGROUND_DELAY_MS = 200;
@@ -430,6 +432,11 @@ export class ShellToolInvocation extends BaseToolInvocation<
} else {
llmContent += ' There was no output before it was cancelled.';
}
if (HEREDOC_REGEX.test(this.params.command)) {
llmContent +=
"\nSuggestion: Large heredoc detected. Please use the 'write_file' tool for better reliability.";
}
} else if (this.params.is_background || result.backgrounded) {
llmContent = `Command moved to background (PID: ${result.pid}). Output hidden. Press Ctrl+B to view.`;
data = {
@@ -468,6 +475,17 @@ export class ShellToolInvocation extends BaseToolInvocation<
llmContentParts.push(`Process Group PGID: ${result.pid}`);
}
const failed =
!!result.error ||
!!result.signal ||
(result.exitCode !== null && result.exitCode !== 0);
if (failed && HEREDOC_REGEX.test(this.params.command)) {
llmContentParts.push(
"Suggestion: Large heredoc detected. Please use the 'write_file' tool for better reliability.",
);
}
llmContent = llmContentParts.join('\n');
}