feat(core): transition to self-describing XML output for subprocess tools

This commit is contained in:
Aishanee Shah
2026-02-16 17:15:25 +00:00
parent 4428c83be4
commit 9e7c1b1984
7 changed files with 45 additions and 189 deletions

View File

@@ -631,17 +631,6 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi
- **Tools vs. Text:** Use tools for actions, text output *only* for communication. Do not add explanatory comments within tool calls.
- **Handling Inability:** If unable/unwilling to fulfill a request, state so briefly without excessive justification. Offer alternatives if appropriate.
## Standard Subprocess Protocol
For any tool that executes a subprocess (including shell commands and project-specific discovered tools), the following information is returned:
- **Output:** The combined content of stdout and stderr. Can be \`(empty)\` or partial on error or for unwaited background processes.
- **Exit Code:** The numeric exit code of the process. Only included if non-zero (indicating failure).
- **Error:** A descriptive message if a process-level error occurred (e.g., command not found).
- **Signal:** The name or number of the signal that terminated the process (if applicable).
- **Background PIDs:** A list of PIDs for any background processes started by the command.
- **Process Group PGID:** The process group ID, which can be used to terminate the process group if needed.
## Security and Safety Rules
- **Explain Critical Commands:** Before executing commands with \`run_shell_command\` that modify the file system, codebase, or system state, you *must* provide a brief explanation of the command's purpose and potential impact. Prioritize user understanding and safety. You should not ask permission to use the tool; the user will be presented with a confirmation dialogue upon use (you do not need to tell them this).
- **Security First:** Always apply security best practices. Never introduce code that exposes, logs, or commits secrets, API keys, or other sensitive information.
@@ -780,17 +769,6 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi
- **Tools vs. Text:** Use tools for actions, text output *only* for communication. Do not add explanatory comments within tool calls.
- **Handling Inability:** If unable/unwilling to fulfill a request, state so briefly without excessive justification. Offer alternatives if appropriate.
## Standard Subprocess Protocol
For any tool that executes a subprocess (including shell commands and project-specific discovered tools), the following information is returned:
- **Output:** The combined content of stdout and stderr. Can be \`(empty)\` or partial on error or for unwaited background processes.
- **Exit Code:** The numeric exit code of the process. Only included if non-zero (indicating failure).
- **Error:** A descriptive message if a process-level error occurred (e.g., command not found).
- **Signal:** The name or number of the signal that terminated the process (if applicable).
- **Background PIDs:** A list of PIDs for any background processes started by the command.
- **Process Group PGID:** The process group ID, which can be used to terminate the process group if needed.
## Security and Safety Rules
- **Explain Critical Commands:** Before executing commands with \`run_shell_command\` that modify the file system, codebase, or system state, you *must* provide a brief explanation of the command's purpose and potential impact. Prioritize user understanding and safety. You should not ask permission to use the tool; the user will be presented with a confirmation dialogue upon use (you do not need to tell them this).
- **Security First:** Always apply security best practices. Never introduce code that exposes, logs, or commits secrets, API keys, or other sensitive information.
@@ -912,17 +890,6 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi
- **Tools vs. Text:** Use tools for actions, text output *only* for communication. Do not add explanatory comments within tool calls.
- **Handling Inability:** If unable/unwilling to fulfill a request, state so briefly without excessive justification. Offer alternatives if appropriate.
## Standard Subprocess Protocol
For any tool that executes a subprocess (including shell commands and project-specific discovered tools), the following information is returned:
- **Output:** The combined content of stdout and stderr. Can be \`(empty)\` or partial on error or for unwaited background processes.
- **Exit Code:** The numeric exit code of the process. Only included if non-zero (indicating failure).
- **Error:** A descriptive message if a process-level error occurred (e.g., command not found).
- **Signal:** The name or number of the signal that terminated the process (if applicable).
- **Background PIDs:** A list of PIDs for any background processes started by the command.
- **Process Group PGID:** The process group ID, which can be used to terminate the process group if needed.
## Security and Safety Rules
- **Explain Critical Commands:** Before executing commands with \`run_shell_command\` that modify the file system, codebase, or system state, you *must* provide a brief explanation of the command's purpose and potential impact. Prioritize user understanding and safety. You should not ask permission to use the tool; the user will be presented with a confirmation dialogue upon use (you do not need to tell them this).
- **Security First:** Always apply security best practices. Never introduce code that exposes, logs, or commits secrets, API keys, or other sensitive information.
@@ -1543,17 +1510,6 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi
- **Tools vs. Text:** Use tools for actions, text output *only* for communication. Do not add explanatory comments within tool calls.
- **Handling Inability:** If unable/unwilling to fulfill a request, state so briefly without excessive justification. Offer alternatives if appropriate.
## Standard Subprocess Protocol
For any tool that executes a subprocess (including shell commands and project-specific discovered tools), the following information is returned:
- **Output:** The combined content of stdout and stderr. Can be \`(empty)\` or partial on error or for unwaited background processes.
- **Exit Code:** The numeric exit code of the process. Only included if non-zero (indicating failure).
- **Error:** A descriptive message if a process-level error occurred (e.g., command not found).
- **Signal:** The name or number of the signal that terminated the process (if applicable).
- **Background PIDs:** A list of PIDs for any background processes started by the command.
- **Process Group PGID:** The process group ID, which can be used to terminate the process group if needed.
## Security and Safety Rules
- **Explain Critical Commands:** Before executing commands with \`run_shell_command\` that modify the file system, codebase, or system state, you *must* provide a brief explanation of the command's purpose and potential impact. Prioritize user understanding and safety. You should not ask permission to use the tool; the user will be presented with a confirmation dialogue upon use (you do not need to tell them this).
- **Security First:** Always apply security best practices. Never introduce code that exposes, logs, or commits secrets, API keys, or other sensitive information.
@@ -1692,17 +1648,6 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi
- **Tools vs. Text:** Use tools for actions, text output *only* for communication. Do not add explanatory comments within tool calls.
- **Handling Inability:** If unable/unwilling to fulfill a request, state so briefly without excessive justification. Offer alternatives if appropriate.
## Standard Subprocess Protocol
For any tool that executes a subprocess (including shell commands and project-specific discovered tools), the following information is returned:
- **Output:** The combined content of stdout and stderr. Can be \`(empty)\` or partial on error or for unwaited background processes.
- **Exit Code:** The numeric exit code of the process. Only included if non-zero (indicating failure).
- **Error:** A descriptive message if a process-level error occurred (e.g., command not found).
- **Signal:** The name or number of the signal that terminated the process (if applicable).
- **Background PIDs:** A list of PIDs for any background processes started by the command.
- **Process Group PGID:** The process group ID, which can be used to terminate the process group if needed.
## Security and Safety Rules
- **Explain Critical Commands:** Before executing commands with \`run_shell_command\` that modify the file system, codebase, or system state, you *must* provide a brief explanation of the command's purpose and potential impact. Prioritize user understanding and safety. You should not ask permission to use the tool; the user will be presented with a confirmation dialogue upon use (you do not need to tell them this).
- **Security First:** Always apply security best practices. Never introduce code that exposes, logs, or commits secrets, API keys, or other sensitive information.
@@ -1845,17 +1790,6 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi
- **Tools vs. Text:** Use tools for actions, text output *only* for communication. Do not add explanatory comments within tool calls.
- **Handling Inability:** If unable/unwilling to fulfill a request, state so briefly without excessive justification. Offer alternatives if appropriate.
## Standard Subprocess Protocol
For any tool that executes a subprocess (including shell commands and project-specific discovered tools), the following information is returned:
- **Output:** The combined content of stdout and stderr. Can be \`(empty)\` or partial on error or for unwaited background processes.
- **Exit Code:** The numeric exit code of the process. Only included if non-zero (indicating failure).
- **Error:** A descriptive message if a process-level error occurred (e.g., command not found).
- **Signal:** The name or number of the signal that terminated the process (if applicable).
- **Background PIDs:** A list of PIDs for any background processes started by the command.
- **Process Group PGID:** The process group ID, which can be used to terminate the process group if needed.
## Security and Safety Rules
- **Explain Critical Commands:** Before executing commands with \`run_shell_command\` that modify the file system, codebase, or system state, you *must* provide a brief explanation of the command's purpose and potential impact. Prioritize user understanding and safety. You should not ask permission to use the tool; the user will be presented with a confirmation dialogue upon use (you do not need to tell them this).
- **Security First:** Always apply security best practices. Never introduce code that exposes, logs, or commits secrets, API keys, or other sensitive information.
@@ -2136,17 +2070,6 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi
- **Tools vs. Text:** Use tools for actions, text output *only* for communication. Do not add explanatory comments within tool calls.
- **Handling Inability:** If unable/unwilling to fulfill a request, state so briefly without excessive justification. Offer alternatives if appropriate.
## Standard Subprocess Protocol
For any tool that executes a subprocess (including shell commands and project-specific discovered tools), the following information is returned:
- **Output:** The combined content of stdout and stderr. Can be \`(empty)\` or partial on error or for unwaited background processes.
- **Exit Code:** The numeric exit code of the process. Only included if non-zero (indicating failure).
- **Error:** A descriptive message if a process-level error occurred (e.g., command not found).
- **Signal:** The name or number of the signal that terminated the process (if applicable).
- **Background PIDs:** A list of PIDs for any background processes started by the command.
- **Process Group PGID:** The process group ID, which can be used to terminate the process group if needed.
## Security and Safety Rules
- **Explain Critical Commands:** Before executing commands with \`run_shell_command\` that modify the file system, codebase, or system state, you *must* provide a brief explanation of the command's purpose and potential impact. Prioritize user understanding and safety. You should not ask permission to use the tool; the user will be presented with a confirmation dialogue upon use (you do not need to tell them this).
- **Security First:** Always apply security best practices. Never introduce code that exposes, logs, or commits secrets, API keys, or other sensitive information.
@@ -2284,17 +2207,6 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi
- **Tools vs. Text:** Use tools for actions, text output *only* for communication. Do not add explanatory comments within tool calls.
- **Handling Inability:** If unable/unwilling to fulfill a request, state so briefly without excessive justification. Offer alternatives if appropriate.
## Standard Subprocess Protocol
For any tool that executes a subprocess (including shell commands and project-specific discovered tools), the following information is returned:
- **Output:** The combined content of stdout and stderr. Can be \`(empty)\` or partial on error or for unwaited background processes.
- **Exit Code:** The numeric exit code of the process. Only included if non-zero (indicating failure).
- **Error:** A descriptive message if a process-level error occurred (e.g., command not found).
- **Signal:** The name or number of the signal that terminated the process (if applicable).
- **Background PIDs:** A list of PIDs for any background processes started by the command.
- **Process Group PGID:** The process group ID, which can be used to terminate the process group if needed.
## Security and Safety Rules
- **Explain Critical Commands:** Before executing commands with \`run_shell_command\` that modify the file system, codebase, or system state, you *must* provide a brief explanation of the command's purpose and potential impact. Prioritize user understanding and safety. You should not ask permission to use the tool; the user will be presented with a confirmation dialogue upon use (you do not need to tell them this).
- **Security First:** Always apply security best practices. Never introduce code that exposes, logs, or commits secrets, API keys, or other sensitive information.
@@ -2433,17 +2345,6 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi
- **Tools vs. Text:** Use tools for actions, text output *only* for communication. Do not add explanatory comments within tool calls.
- **Handling Inability:** If unable/unwilling to fulfill a request, state so briefly without excessive justification. Offer alternatives if appropriate.
## Standard Subprocess Protocol
For any tool that executes a subprocess (including shell commands and project-specific discovered tools), the following information is returned:
- **Output:** The combined content of stdout and stderr. Can be \`(empty)\` or partial on error or for unwaited background processes.
- **Exit Code:** The numeric exit code of the process. Only included if non-zero (indicating failure).
- **Error:** A descriptive message if a process-level error occurred (e.g., command not found).
- **Signal:** The name or number of the signal that terminated the process (if applicable).
- **Background PIDs:** A list of PIDs for any background processes started by the command.
- **Process Group PGID:** The process group ID, which can be used to terminate the process group if needed.
## Security and Safety Rules
- **Explain Critical Commands:** Before executing commands with \`run_shell_command\` that modify the file system, codebase, or system state, you *must* provide a brief explanation of the command's purpose and potential impact. Prioritize user understanding and safety. You should not ask permission to use the tool; the user will be presented with a confirmation dialogue upon use (you do not need to tell them this).
- **Security First:** Always apply security best practices. Never introduce code that exposes, logs, or commits secrets, API keys, or other sensitive information.
@@ -2821,17 +2722,6 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi
- **Tools vs. Text:** Use tools for actions, text output *only* for communication. Do not add explanatory comments within tool calls.
- **Handling Inability:** If unable/unwilling to fulfill a request, state so briefly without excessive justification. Offer alternatives if appropriate.
## Standard Subprocess Protocol
For any tool that executes a subprocess (including shell commands and project-specific discovered tools), the following information is returned:
- **Output:** The combined content of stdout and stderr. Can be \`(empty)\` or partial on error or for unwaited background processes.
- **Exit Code:** The numeric exit code of the process. Only included if non-zero (indicating failure).
- **Error:** A descriptive message if a process-level error occurred (e.g., command not found).
- **Signal:** The name or number of the signal that terminated the process (if applicable).
- **Background PIDs:** A list of PIDs for any background processes started by the command.
- **Process Group PGID:** The process group ID, which can be used to terminate the process group if needed.
## Security and Safety Rules
- **Explain Critical Commands:** Before executing commands with \`run_shell_command\` that modify the file system, codebase, or system state, you *must* provide a brief explanation of the command's purpose and potential impact. Prioritize user understanding and safety. You should not ask permission to use the tool; the user will be presented with a confirmation dialogue upon use (you do not need to tell them this).
- **Security First:** Always apply security best practices. Never introduce code that exposes, logs, or commits secrets, API keys, or other sensitive information.
@@ -2970,17 +2860,6 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi
- **Tools vs. Text:** Use tools for actions, text output *only* for communication. Do not add explanatory comments within tool calls.
- **Handling Inability:** If unable/unwilling to fulfill a request, state so briefly without excessive justification. Offer alternatives if appropriate.
## Standard Subprocess Protocol
For any tool that executes a subprocess (including shell commands and project-specific discovered tools), the following information is returned:
- **Output:** The combined content of stdout and stderr. Can be \`(empty)\` or partial on error or for unwaited background processes.
- **Exit Code:** The numeric exit code of the process. Only included if non-zero (indicating failure).
- **Error:** A descriptive message if a process-level error occurred (e.g., command not found).
- **Signal:** The name or number of the signal that terminated the process (if applicable).
- **Background PIDs:** A list of PIDs for any background processes started by the command.
- **Process Group PGID:** The process group ID, which can be used to terminate the process group if needed.
## Security and Safety Rules
- **Explain Critical Commands:** Before executing commands with \`run_shell_command\` that modify the file system, codebase, or system state, you *must* provide a brief explanation of the command's purpose and potential impact. Prioritize user understanding and safety. You should not ask permission to use the tool; the user will be presented with a confirmation dialogue upon use (you do not need to tell them this).
- **Security First:** Always apply security best practices. Never introduce code that exposes, logs, or commits secrets, API keys, or other sensitive information.
@@ -3230,17 +3109,6 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi
- **Tools vs. Text:** Use tools for actions, text output *only* for communication. Do not add explanatory comments within tool calls.
- **Handling Inability:** If unable/unwilling to fulfill a request, state so briefly without excessive justification. Offer alternatives if appropriate.
## Standard Subprocess Protocol
For any tool that executes a subprocess (including shell commands and project-specific discovered tools), the following information is returned:
- **Output:** The combined content of stdout and stderr. Can be \`(empty)\` or partial on error or for unwaited background processes.
- **Exit Code:** The numeric exit code of the process. Only included if non-zero (indicating failure).
- **Error:** A descriptive message if a process-level error occurred (e.g., command not found).
- **Signal:** The name or number of the signal that terminated the process (if applicable).
- **Background PIDs:** A list of PIDs for any background processes started by the command.
- **Process Group PGID:** The process group ID, which can be used to terminate the process group if needed.
## Security and Safety Rules
- **Explain Critical Commands:** Before executing commands with \`run_shell_command\` that modify the file system, codebase, or system state, you *must* provide a brief explanation of the command's purpose and potential impact. Prioritize user understanding and safety. You should not ask permission to use the tool; the user will be presented with a confirmation dialogue upon use (you do not need to tell them this).
- **Security First:** Always apply security best practices. Never introduce code that exposes, logs, or commits secrets, API keys, or other sensitive information.
@@ -3379,17 +3247,6 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi
- **Tools vs. Text:** Use tools for actions, text output *only* for communication. Do not add explanatory comments within tool calls.
- **Handling Inability:** If unable/unwilling to fulfill a request, state so briefly without excessive justification. Offer alternatives if appropriate.
## Standard Subprocess Protocol
For any tool that executes a subprocess (including shell commands and project-specific discovered tools), the following information is returned:
- **Output:** The combined content of stdout and stderr. Can be \`(empty)\` or partial on error or for unwaited background processes.
- **Exit Code:** The numeric exit code of the process. Only included if non-zero (indicating failure).
- **Error:** A descriptive message if a process-level error occurred (e.g., command not found).
- **Signal:** The name or number of the signal that terminated the process (if applicable).
- **Background PIDs:** A list of PIDs for any background processes started by the command.
- **Process Group PGID:** The process group ID, which can be used to terminate the process group if needed.
## Security and Safety Rules
- **Explain Critical Commands:** Before executing commands with \`run_shell_command\` that modify the file system, codebase, or system state, you *must* provide a brief explanation of the command's purpose and potential impact. Prioritize user understanding and safety. You should not ask permission to use the tool; the user will be presented with a confirmation dialogue upon use (you do not need to tell them this).
- **Security First:** Always apply security best practices. Never introduce code that exposes, logs, or commits secrets, API keys, or other sensitive information.

View File

@@ -5,9 +5,7 @@ exports[`ShellTool > getDescription > should return the non-windows description
Efficiency Guidelines:
- Quiet Flags: Always prefer silent or quiet flags (e.g., \`npm install --silent\`, \`git --no-pager\`) to reduce output volume while still capturing necessary information.
- Pagination: Always disable terminal pagination to ensure commands terminate (e.g., use \`git --no-pager\`, \`systemctl --no-pager\`, or set \`PAGER=cat\`).
The following information is returned: [Protocol: Subprocess]"
- Pagination: Always disable terminal pagination to ensure commands terminate (e.g., use \`git --no-pager\`, \`systemctl --no-pager\`, or set \`PAGER=cat\`)."
`;
exports[`ShellTool > getDescription > should return the windows description when on windows 1`] = `
@@ -15,9 +13,7 @@ exports[`ShellTool > getDescription > should return the windows description when
Efficiency Guidelines:
- Quiet Flags: Always prefer silent or quiet flags (e.g., \`npm install --silent\`, \`git --no-pager\`) to reduce output volume while still capturing necessary information.
- Pagination: Always disable terminal pagination to ensure commands terminate (e.g., use \`git --no-pager\`, \`systemctl --no-pager\`, or set \`PAGER=cat\`).
The following information is returned: [Protocol: Subprocess]"
- Pagination: Always disable terminal pagination to ensure commands terminate (e.g., use \`git --no-pager\`, \`systemctl --no-pager\`, or set \`PAGER=cat\`)."
`;
exports[`ShellTool > getSchema > should return the base schema when no modelId is provided 1`] = `
@@ -25,9 +21,7 @@ exports[`ShellTool > getSchema > should return the base schema when no modelId i
Efficiency Guidelines:
- Quiet Flags: Always prefer silent or quiet flags (e.g., \`npm install --silent\`, \`git --no-pager\`) to reduce output volume while still capturing necessary information.
- Pagination: Always disable terminal pagination to ensure commands terminate (e.g., use \`git --no-pager\`, \`systemctl --no-pager\`, or set \`PAGER=cat\`).
The following information is returned: [Protocol: Subprocess]"
- Pagination: Always disable terminal pagination to ensure commands terminate (e.g., use \`git --no-pager\`, \`systemctl --no-pager\`, or set \`PAGER=cat\`)."
`;
exports[`ShellTool > getSchema > should return the schema from the resolver when modelId is provided 1`] = `
@@ -35,7 +29,5 @@ exports[`ShellTool > getSchema > should return the schema from the resolver when
Efficiency Guidelines:
- Quiet Flags: Always prefer silent or quiet flags (e.g., \`npm install --silent\`, \`git --no-pager\`) to reduce output volume while still capturing necessary information.
- Pagination: Always disable terminal pagination to ensure commands terminate (e.g., use \`git --no-pager\`, \`systemctl --no-pager\`, or set \`PAGER=cat\`).
The following information is returned: [Protocol: Subprocess]"
- Pagination: Always disable terminal pagination to ensure commands terminate (e.g., use \`git --no-pager\`, \`systemctl --no-pager\`, or set \`PAGER=cat\`)."
`;

View File

@@ -572,9 +572,7 @@ exports[`coreTools snapshots for specific models > Model: gemini-2.5-pro > snaps
Efficiency Guidelines:
- Quiet Flags: Always prefer silent or quiet flags (e.g., \`npm install --silent\`, \`git --no-pager\`) to reduce output volume while still capturing necessary information.
- Pagination: Always disable terminal pagination to ensure commands terminate (e.g., use \`git --no-pager\`, \`systemctl --no-pager\`, or set \`PAGER=cat\`).
The following information is returned: [Protocol: Subprocess]",
- Pagination: Always disable terminal pagination to ensure commands terminate (e.g., use \`git --no-pager\`, \`systemctl --no-pager\`, or set \`PAGER=cat\`).",
"name": "run_shell_command",
"parametersJsonSchema": {
"properties": {
@@ -1354,9 +1352,7 @@ exports[`coreTools snapshots for specific models > Model: gemini-3-pro-preview >
Efficiency Guidelines:
- Quiet Flags: Always prefer silent or quiet flags (e.g., \`npm install --silent\`, \`git --no-pager\`) to reduce output volume while still capturing necessary information.
- Pagination: Always disable terminal pagination to ensure commands terminate (e.g., use \`git --no-pager\`, \`systemctl --no-pager\`, or set \`PAGER=cat\`).
The following information is returned: [Protocol: Subprocess]",
- Pagination: Always disable terminal pagination to ensure commands terminate (e.g., use \`git --no-pager\`, \`systemctl --no-pager\`, or set \`PAGER=cat\`).",
"name": "run_shell_command",
"parametersJsonSchema": {
"properties": {

View File

@@ -278,7 +278,9 @@ describe('ShellTool', () => {
false,
{ pager: 'cat', sanitizationConfig: {} },
);
expect(result.llmContent).toContain('Background PIDs: 54322');
expect(result.llmContent).toContain(
'<background_pids>54322</background_pids>',
);
// The file should be deleted by the tool
expect(fs.existsSync(tmpFile)).toBe(false);
});
@@ -390,7 +392,9 @@ describe('ShellTool', () => {
});
const result = await promise;
expect(result.llmContent).toContain('Error: wrapped command failed');
expect(result.llmContent).toContain(
'<error>wrapped command failed</error>',
);
expect(result.llmContent).not.toContain('pgrep');
});
@@ -689,7 +693,7 @@ describe('ShellTool', () => {
resolveShellExecution({ output: 'hello', exitCode: 0 });
const result = await promise;
expect(result.llmContent).not.toContain('Exit Code:');
expect(result.llmContent).not.toContain('<exit_code>');
});
it('should include Exit Code when command fails (non-zero exit code)', async () => {
@@ -698,7 +702,7 @@ describe('ShellTool', () => {
resolveShellExecution({ output: '', exitCode: 1 });
const result = await promise;
expect(result.llmContent).toContain('Exit Code: 1');
expect(result.llmContent).toContain('<exit_code>1</exit_code>');
});
it('should not include Error when there is no process error', async () => {
@@ -707,7 +711,7 @@ describe('ShellTool', () => {
resolveShellExecution({ output: 'hello', exitCode: 0, error: null });
const result = await promise;
expect(result.llmContent).not.toContain('Error:');
expect(result.llmContent).not.toContain('<error>');
});
it('should include Error when there is a process error', async () => {
@@ -720,7 +724,7 @@ describe('ShellTool', () => {
});
const result = await promise;
expect(result.llmContent).toContain('Error: spawn ENOENT');
expect(result.llmContent).toContain('<error>spawn ENOENT</error>');
});
it('should not include Signal when there is no signal', async () => {
@@ -729,7 +733,7 @@ describe('ShellTool', () => {
resolveShellExecution({ output: 'hello', exitCode: 0, signal: null });
const result = await promise;
expect(result.llmContent).not.toContain('Signal:');
expect(result.llmContent).not.toContain('<signal>');
});
it('should include Signal when process was killed by signal', async () => {
@@ -742,7 +746,7 @@ describe('ShellTool', () => {
});
const result = await promise;
expect(result.llmContent).toContain('Signal: 9');
expect(result.llmContent).toContain('<signal>9</signal>');
});
it('should not include Background PIDs when there are none', async () => {
@@ -751,7 +755,7 @@ describe('ShellTool', () => {
resolveShellExecution({ output: 'hello', exitCode: 0 });
const result = await promise;
expect(result.llmContent).not.toContain('Background PIDs:');
expect(result.llmContent).not.toContain('<background_pids>');
});
it('should not include Process Group PGID when pid is not set', async () => {
@@ -760,7 +764,7 @@ describe('ShellTool', () => {
resolveShellExecution({ output: 'hello', exitCode: 0, pid: undefined });
const result = await promise;
expect(result.llmContent).not.toContain('Process Group PGID:');
expect(result.llmContent).not.toContain('<process_group_pgid>');
});
it('should have minimal output for successful command', async () => {
@@ -769,8 +773,9 @@ describe('ShellTool', () => {
resolveShellExecution({ output: 'hello', exitCode: 0, pid: undefined });
const result = await promise;
// Should only contain Output field
expect(result.llmContent).toBe('Output: hello');
// Should only contain subprocess_result and output
expect(result.llmContent).toContain('<subprocess_result>');
expect(result.llmContent).toContain('<output>hello</output>');
});
});

View File

@@ -354,31 +354,36 @@ export class ShellToolInvocation extends BaseToolInvocation<
} else {
// Create a formatted error string for display, replacing the wrapper command
// with the user-facing command.
const llmContentParts = [`Output: ${result.output || '(empty)'}`];
const output = result.output || '(empty)';
const parts = [`<output>${output}</output>`];
if (result.error) {
const finalError = result.error.message.replaceAll(
commandToExecute,
this.params.command,
);
llmContentParts.push(`Error: ${finalError}`);
parts.push(`<error>${finalError}</error>`);
}
if (result.exitCode !== null && result.exitCode !== 0) {
llmContentParts.push(`Exit Code: ${result.exitCode}`);
parts.push(`<exit_code>${result.exitCode}</exit_code>`);
}
if (result.signal) {
llmContentParts.push(`Signal: ${result.signal}`);
parts.push(`<signal>${result.signal}</signal>`);
}
if (backgroundPIDs.length) {
llmContentParts.push(`Background PIDs: ${backgroundPIDs.join(', ')}`);
parts.push(
`<background_pids>${backgroundPIDs.join(', ')}</background_pids>`,
);
}
if (result.pid) {
llmContentParts.push(`Process Group PGID: ${result.pid}`);
parts.push(`<process_group_pgid>${result.pid}</process_group_pgid>`);
}
llmContent = llmContentParts.join('\n');
llmContent = `<subprocess_result>\n${parts
.map((p) => ` ${p}`)
.join('\n')}\n</subprocess_result>`;
}
let returnDisplayMessage = '';

View File

@@ -550,8 +550,10 @@ describe('ToolRegistry', () => {
expect(result.error?.type).toBe(
ToolErrorType.DISCOVERED_TOOL_EXECUTION_ERROR,
);
expect(result.llmContent).toContain('Output: Something went wrong');
expect(result.llmContent).toContain('Exit Code: 1');
expect(result.llmContent).toContain(
'<output>Something went wrong</output>',
);
expect(result.llmContent).toContain('<exit_code>1</exit_code>');
});
it('should pass MessageBus to DiscoveredTool and its invocations', async () => {

View File

@@ -103,19 +103,19 @@ class DiscoveredToolInvocation extends BaseToolInvocation<
// if there is any error, non-zero exit code, signal, or stderr, return error details instead of stdout
if (error || code !== 0 || signal || stderr) {
const llmContentParts = [
`Output: ${(stdout + stderr).trim() || '(empty)'}`,
const parts = [
`<output>${(stdout + stderr).trim() || '(empty)'}</output>`,
];
if (error) {
llmContentParts.push(`Error: ${error}`);
parts.push(`<error>${error}</error>`);
}
if (code !== null && code !== 0) {
llmContentParts.push(`Exit Code: ${code}`);
parts.push(`<exit_code>${code}</exit_code>`);
}
if (signal) {
llmContentParts.push(`Signal: ${signal}`);
parts.push(`<signal>${signal}</signal>`);
}
const llmContent = llmContentParts.join('\n');
const llmContent = `<subprocess_result>\n${parts.map((p) => ` ${p}`).join('\n')}\n</subprocess_result>`;
return {
llmContent,
returnDisplay: llmContent,
@@ -159,7 +159,6 @@ Tool discovery and call commands can be configured in project or user settings.
When called, the tool call command is executed as a subprocess.
On success, tool output is returned as a json string.
Otherwise, the following information is returned: [Protocol: Subprocess]
`;
super(
prefixedName,