Files
llmx/codex-cli/src/components/chat/terminal-chat.tsx

730 lines
25 KiB
TypeScript
Raw Normal View History

import type { ApplyPatchCommand, ApprovalPolicy } from "../../approvals.js";
import type { CommandConfirmation } from "../../utils/agent/agent-loop.js";
import type { AppConfig } from "../../utils/config.js";
import type { ColorName } from "chalk";
import type { ResponseItem } from "openai/resources/responses/responses.mjs";
import TerminalChatInput from "./terminal-chat-input.js";
import { TerminalChatToolCallCommand } from "./terminal-chat-tool-call-command.js";
import TerminalMessageHistory from "./terminal-message-history.js";
import { formatCommandForDisplay } from "../../format-command.js";
import { useConfirmation } from "../../hooks/use-confirmation.js";
import { useTerminalSize } from "../../hooks/use-terminal-size.js";
import { AgentLoop } from "../../utils/agent/agent-loop.js";
feat: shell command explanation option (#173) # Shell Command Explanation Option ## Description This PR adds an option to explain shell commands when the user is prompted to approve them (Fixes #110). When reviewing a shell command, users can now select "Explain this command" to get a detailed explanation of what the command does before deciding whether to approve or reject it. ## Changes - Added a new "EXPLAIN" option to the `ReviewDecision` enum - Updated the command review UI to include an "Explain this command (x)" option - Implemented the logic to send the command to the LLM for explanation using the same model as the agent - Added a display for the explanation in the command review UI - Updated all relevant components to pass the explanation through the component tree ## Benefits - Improves user understanding of shell commands before approving them - Reduces the risk of approving potentially harmful commands - Enhances the educational aspect of the tool, helping users learn about shell commands - Maintains the same workflow with minimal UI changes ## Testing - Manually tested the explanation feature with various shell commands - Verified that the explanation is displayed correctly in the UI - Confirmed that the user can still approve or reject the command after viewing the explanation ## Screenshots ![improved_shell_explanation_demo](https://github.com/user-attachments/assets/05923481-29db-4eba-9cc6-5e92301d2be0) ## Additional Notes The explanation is generated using the same model as the agent, ensuring consistency in the quality and style of explanations. --------- Signed-off-by: crazywolf132 <crazywolf132@gmail.com>
2025-04-18 06:28:58 +10:00
import { ReviewDecision } from "../../utils/agent/review.js";
import { generateCompactSummary } from "../../utils/compact-summary.js";
Adds Azure OpenAI support (#769) ## Summary This PR introduces support for Azure OpenAI as a provider within the Codex CLI. Users can now configure the tool to leverage their Azure OpenAI deployments by specifying `"azure"` as the provider in `config.json` and setting the corresponding `AZURE_OPENAI_API_KEY` and `AZURE_OPENAI_API_VERSION` environment variables. This functionality is added alongside the existing provider options (OpenAI, OpenRouter, etc.). Related to #92 **Note:** This PR is currently in **Draft** status because tests on the `main` branch are failing. It will be marked as ready for review once the `main` branch is stable and tests are passing. --- ## What’s Changed - **Configuration (`config.ts`, `providers.ts`, `README.md`):** - Added `"azure"` to the supported `providers` list in `providers.ts`, specifying its name, default base URL structure, and environment variable key (`AZURE_OPENAI_API_KEY`). - Defined the `AZURE_OPENAI_API_VERSION` environment variable in `config.ts` with a default value (`2025-03-01-preview`). - Updated `README.md` to: - Include "azure" in the list of providers. - Add a configuration section for Azure OpenAI, detailing the required environment variables (`AZURE_OPENAI_API_KEY`, `AZURE_OPENAI_API_VERSION`) with examples. - **Client Instantiation (`terminal-chat.tsx`, `singlepass-cli-app.tsx`, `agent-loop.ts`, `compact-summary.ts`, `model-utils.ts`):** - Modified various components and utility functions where the OpenAI client is initialized. - Added conditional logic to check if the configured `provider` is `"azure"`. - If the provider is Azure, the `AzureOpenAI` client from the `openai` package is instantiated, using the configured `baseURL`, `apiKey` (from `AZURE_OPENAI_API_KEY`), and `apiVersion` (from `AZURE_OPENAI_API_VERSION`). - Otherwise, the standard `OpenAI` client is instantiated as before. - **Dependencies:** - Relies on the `openai` package's built-in support for `AzureOpenAI`. No *new* external dependencies were added specifically for this Azure implementation beyond the `openai` package itself. --- ## How to Test *This has been tested locally and confirmed working with Azure OpenAI.* 1. **Configure `config.json`:** Ensure your `~/.codex/config.json` (or project-specific config) includes Azure and sets it as the active provider: ```json { "providers": { // ... other providers "azure": { "name": "AzureOpenAI", "baseURL": "https://YOUR_RESOURCE_NAME.openai.azure.com", // Replace with your Azure endpoint "envKey": "AZURE_OPENAI_API_KEY" } }, "provider": "azure", // Set Azure as the active provider "model": "o4-mini" // Use your Azure deployment name here // ... other config settings } ``` 2. **Set up Environment Variables:** ```bash # Set the API Key for your Azure OpenAI resource export AZURE_OPENAI_API_KEY="your-azure-api-key-here" # Set the API Version (Optional - defaults to `2025-03-01-preview` if not set) # Ensure this version is supported by your Azure deployment and endpoint export AZURE_OPENAI_API_VERSION="2025-03-01-preview" ``` 3. **Get the Codex CLI by building from this PR branch:** Clone your fork, checkout this branch (`feat/azure-openai`), navigate to `codex-cli`, and build: ```bash # cd /path/to/your/fork/codex git checkout feat/azure-openai # Or your branch name cd codex-cli corepack enable pnpm install pnpm build ``` 4. **Invoke Codex:** Run the locally built CLI using `node` from the `codex-cli` directory: ```bash node ./dist/cli.js "Explain the purpose of this PR" ``` *(Alternatively, if you ran `pnpm link` after building, you can use `codex "Explain the purpose of this PR"` from anywhere)*. 5. **Verify:** Confirm that the command executes successfully and interacts with your configured Azure OpenAI deployment. --- ## Tests - [x] Tested locally against an Azure OpenAI deployment using API Key authentication. Basic commands and interactions confirmed working. --- ## Checklist - [x] Added Azure provider details to configuration files (`providers.ts`, `config.ts`). - [x] Implemented conditional `AzureOpenAI` client initialization based on provider setting. - [x] Ensured `apiVersion` is passed correctly to the Azure client. - [x] Updated `README.md` with Azure OpenAI setup instructions. - [x] Manually tested core functionality against a live Azure OpenAI endpoint. - [x] Add/update automated tests for the Azure code path (pending `main` stability). cc @theabhinavdas @nikodem-wrona @fouad-openai @tibo-openai (adjust as needed) --- I have read the CLA Document and I hereby sign the CLA
2025-05-09 18:11:32 -07:00
import { saveConfig } from "../../utils/config.js";
import { extractAppliedPatches as _extractAppliedPatches } from "../../utils/extract-applied-patches.js";
import { getGitDiff } from "../../utils/get-diff.js";
import { createInputItem } from "../../utils/input-utils.js";
import { log } from "../../utils/logger/log.js";
import {
getAvailableModels,
calculateContextPercentRemaining,
uniqueById,
} from "../../utils/model-utils.js";
Adds Azure OpenAI support (#769) ## Summary This PR introduces support for Azure OpenAI as a provider within the Codex CLI. Users can now configure the tool to leverage their Azure OpenAI deployments by specifying `"azure"` as the provider in `config.json` and setting the corresponding `AZURE_OPENAI_API_KEY` and `AZURE_OPENAI_API_VERSION` environment variables. This functionality is added alongside the existing provider options (OpenAI, OpenRouter, etc.). Related to #92 **Note:** This PR is currently in **Draft** status because tests on the `main` branch are failing. It will be marked as ready for review once the `main` branch is stable and tests are passing. --- ## What’s Changed - **Configuration (`config.ts`, `providers.ts`, `README.md`):** - Added `"azure"` to the supported `providers` list in `providers.ts`, specifying its name, default base URL structure, and environment variable key (`AZURE_OPENAI_API_KEY`). - Defined the `AZURE_OPENAI_API_VERSION` environment variable in `config.ts` with a default value (`2025-03-01-preview`). - Updated `README.md` to: - Include "azure" in the list of providers. - Add a configuration section for Azure OpenAI, detailing the required environment variables (`AZURE_OPENAI_API_KEY`, `AZURE_OPENAI_API_VERSION`) with examples. - **Client Instantiation (`terminal-chat.tsx`, `singlepass-cli-app.tsx`, `agent-loop.ts`, `compact-summary.ts`, `model-utils.ts`):** - Modified various components and utility functions where the OpenAI client is initialized. - Added conditional logic to check if the configured `provider` is `"azure"`. - If the provider is Azure, the `AzureOpenAI` client from the `openai` package is instantiated, using the configured `baseURL`, `apiKey` (from `AZURE_OPENAI_API_KEY`), and `apiVersion` (from `AZURE_OPENAI_API_VERSION`). - Otherwise, the standard `OpenAI` client is instantiated as before. - **Dependencies:** - Relies on the `openai` package's built-in support for `AzureOpenAI`. No *new* external dependencies were added specifically for this Azure implementation beyond the `openai` package itself. --- ## How to Test *This has been tested locally and confirmed working with Azure OpenAI.* 1. **Configure `config.json`:** Ensure your `~/.codex/config.json` (or project-specific config) includes Azure and sets it as the active provider: ```json { "providers": { // ... other providers "azure": { "name": "AzureOpenAI", "baseURL": "https://YOUR_RESOURCE_NAME.openai.azure.com", // Replace with your Azure endpoint "envKey": "AZURE_OPENAI_API_KEY" } }, "provider": "azure", // Set Azure as the active provider "model": "o4-mini" // Use your Azure deployment name here // ... other config settings } ``` 2. **Set up Environment Variables:** ```bash # Set the API Key for your Azure OpenAI resource export AZURE_OPENAI_API_KEY="your-azure-api-key-here" # Set the API Version (Optional - defaults to `2025-03-01-preview` if not set) # Ensure this version is supported by your Azure deployment and endpoint export AZURE_OPENAI_API_VERSION="2025-03-01-preview" ``` 3. **Get the Codex CLI by building from this PR branch:** Clone your fork, checkout this branch (`feat/azure-openai`), navigate to `codex-cli`, and build: ```bash # cd /path/to/your/fork/codex git checkout feat/azure-openai # Or your branch name cd codex-cli corepack enable pnpm install pnpm build ``` 4. **Invoke Codex:** Run the locally built CLI using `node` from the `codex-cli` directory: ```bash node ./dist/cli.js "Explain the purpose of this PR" ``` *(Alternatively, if you ran `pnpm link` after building, you can use `codex "Explain the purpose of this PR"` from anywhere)*. 5. **Verify:** Confirm that the command executes successfully and interacts with your configured Azure OpenAI deployment. --- ## Tests - [x] Tested locally against an Azure OpenAI deployment using API Key authentication. Basic commands and interactions confirmed working. --- ## Checklist - [x] Added Azure provider details to configuration files (`providers.ts`, `config.ts`). - [x] Implemented conditional `AzureOpenAI` client initialization based on provider setting. - [x] Ensured `apiVersion` is passed correctly to the Azure client. - [x] Updated `README.md` with Azure OpenAI setup instructions. - [x] Manually tested core functionality against a live Azure OpenAI endpoint. - [x] Add/update automated tests for the Azure code path (pending `main` stability). cc @theabhinavdas @nikodem-wrona @fouad-openai @tibo-openai (adjust as needed) --- I have read the CLA Document and I hereby sign the CLA
2025-05-09 18:11:32 -07:00
import { createOpenAIClient } from "../../utils/openai-client.js";
import { CLI_VERSION } from "../../utils/session.js";
import { shortCwd } from "../../utils/short-path.js";
import { saveRollout } from "../../utils/storage/save-rollout.js";
import ApprovalModeOverlay from "../approval-mode-overlay.js";
import DiffOverlay from "../diff-overlay.js";
import HelpOverlay from "../help-overlay.js";
import HistoryOverlay from "../history-overlay.js";
import ModelOverlay from "../model-overlay.js";
import chalk from "chalk";
import { Box, Text } from "ink";
import { spawn } from "node:child_process";
import React, { useEffect, useMemo, useRef, useState } from "react";
import { inspect } from "util";
export type OverlayModeType =
| "none"
| "history"
| "model"
| "approval"
| "help"
| "diff";
type Props = {
config: AppConfig;
prompt?: string;
imagePaths?: Array<string>;
approvalPolicy: ApprovalPolicy;
additionalWritableRoots: ReadonlyArray<string>;
fullStdout: boolean;
};
const colorsByPolicy: Record<ApprovalPolicy, ColorName | undefined> = {
"suggest": undefined,
"auto-edit": "greenBright",
"full-auto": "green",
};
feat: shell command explanation option (#173) # Shell Command Explanation Option ## Description This PR adds an option to explain shell commands when the user is prompted to approve them (Fixes #110). When reviewing a shell command, users can now select "Explain this command" to get a detailed explanation of what the command does before deciding whether to approve or reject it. ## Changes - Added a new "EXPLAIN" option to the `ReviewDecision` enum - Updated the command review UI to include an "Explain this command (x)" option - Implemented the logic to send the command to the LLM for explanation using the same model as the agent - Added a display for the explanation in the command review UI - Updated all relevant components to pass the explanation through the component tree ## Benefits - Improves user understanding of shell commands before approving them - Reduces the risk of approving potentially harmful commands - Enhances the educational aspect of the tool, helping users learn about shell commands - Maintains the same workflow with minimal UI changes ## Testing - Manually tested the explanation feature with various shell commands - Verified that the explanation is displayed correctly in the UI - Confirmed that the user can still approve or reject the command after viewing the explanation ## Screenshots ![improved_shell_explanation_demo](https://github.com/user-attachments/assets/05923481-29db-4eba-9cc6-5e92301d2be0) ## Additional Notes The explanation is generated using the same model as the agent, ensuring consistency in the quality and style of explanations. --------- Signed-off-by: crazywolf132 <crazywolf132@gmail.com>
2025-04-18 06:28:58 +10:00
/**
* Generates an explanation for a shell command using the OpenAI API.
*
* @param command The command to explain
* @param model The model to use for generating the explanation
* @param flexMode Whether to use the flex-mode service tier
* @param config The configuration object
feat: shell command explanation option (#173) # Shell Command Explanation Option ## Description This PR adds an option to explain shell commands when the user is prompted to approve them (Fixes #110). When reviewing a shell command, users can now select "Explain this command" to get a detailed explanation of what the command does before deciding whether to approve or reject it. ## Changes - Added a new "EXPLAIN" option to the `ReviewDecision` enum - Updated the command review UI to include an "Explain this command (x)" option - Implemented the logic to send the command to the LLM for explanation using the same model as the agent - Added a display for the explanation in the command review UI - Updated all relevant components to pass the explanation through the component tree ## Benefits - Improves user understanding of shell commands before approving them - Reduces the risk of approving potentially harmful commands - Enhances the educational aspect of the tool, helping users learn about shell commands - Maintains the same workflow with minimal UI changes ## Testing - Manually tested the explanation feature with various shell commands - Verified that the explanation is displayed correctly in the UI - Confirmed that the user can still approve or reject the command after viewing the explanation ## Screenshots ![improved_shell_explanation_demo](https://github.com/user-attachments/assets/05923481-29db-4eba-9cc6-5e92301d2be0) ## Additional Notes The explanation is generated using the same model as the agent, ensuring consistency in the quality and style of explanations. --------- Signed-off-by: crazywolf132 <crazywolf132@gmail.com>
2025-04-18 06:28:58 +10:00
* @returns A human-readable explanation of what the command does
*/
async function generateCommandExplanation(
command: Array<string>,
model: string,
flexMode: boolean,
config: AppConfig,
feat: shell command explanation option (#173) # Shell Command Explanation Option ## Description This PR adds an option to explain shell commands when the user is prompted to approve them (Fixes #110). When reviewing a shell command, users can now select "Explain this command" to get a detailed explanation of what the command does before deciding whether to approve or reject it. ## Changes - Added a new "EXPLAIN" option to the `ReviewDecision` enum - Updated the command review UI to include an "Explain this command (x)" option - Implemented the logic to send the command to the LLM for explanation using the same model as the agent - Added a display for the explanation in the command review UI - Updated all relevant components to pass the explanation through the component tree ## Benefits - Improves user understanding of shell commands before approving them - Reduces the risk of approving potentially harmful commands - Enhances the educational aspect of the tool, helping users learn about shell commands - Maintains the same workflow with minimal UI changes ## Testing - Manually tested the explanation feature with various shell commands - Verified that the explanation is displayed correctly in the UI - Confirmed that the user can still approve or reject the command after viewing the explanation ## Screenshots ![improved_shell_explanation_demo](https://github.com/user-attachments/assets/05923481-29db-4eba-9cc6-5e92301d2be0) ## Additional Notes The explanation is generated using the same model as the agent, ensuring consistency in the quality and style of explanations. --------- Signed-off-by: crazywolf132 <crazywolf132@gmail.com>
2025-04-18 06:28:58 +10:00
): Promise<string> {
try {
// Create a temporary OpenAI client
Adds Azure OpenAI support (#769) ## Summary This PR introduces support for Azure OpenAI as a provider within the Codex CLI. Users can now configure the tool to leverage their Azure OpenAI deployments by specifying `"azure"` as the provider in `config.json` and setting the corresponding `AZURE_OPENAI_API_KEY` and `AZURE_OPENAI_API_VERSION` environment variables. This functionality is added alongside the existing provider options (OpenAI, OpenRouter, etc.). Related to #92 **Note:** This PR is currently in **Draft** status because tests on the `main` branch are failing. It will be marked as ready for review once the `main` branch is stable and tests are passing. --- ## What’s Changed - **Configuration (`config.ts`, `providers.ts`, `README.md`):** - Added `"azure"` to the supported `providers` list in `providers.ts`, specifying its name, default base URL structure, and environment variable key (`AZURE_OPENAI_API_KEY`). - Defined the `AZURE_OPENAI_API_VERSION` environment variable in `config.ts` with a default value (`2025-03-01-preview`). - Updated `README.md` to: - Include "azure" in the list of providers. - Add a configuration section for Azure OpenAI, detailing the required environment variables (`AZURE_OPENAI_API_KEY`, `AZURE_OPENAI_API_VERSION`) with examples. - **Client Instantiation (`terminal-chat.tsx`, `singlepass-cli-app.tsx`, `agent-loop.ts`, `compact-summary.ts`, `model-utils.ts`):** - Modified various components and utility functions where the OpenAI client is initialized. - Added conditional logic to check if the configured `provider` is `"azure"`. - If the provider is Azure, the `AzureOpenAI` client from the `openai` package is instantiated, using the configured `baseURL`, `apiKey` (from `AZURE_OPENAI_API_KEY`), and `apiVersion` (from `AZURE_OPENAI_API_VERSION`). - Otherwise, the standard `OpenAI` client is instantiated as before. - **Dependencies:** - Relies on the `openai` package's built-in support for `AzureOpenAI`. No *new* external dependencies were added specifically for this Azure implementation beyond the `openai` package itself. --- ## How to Test *This has been tested locally and confirmed working with Azure OpenAI.* 1. **Configure `config.json`:** Ensure your `~/.codex/config.json` (or project-specific config) includes Azure and sets it as the active provider: ```json { "providers": { // ... other providers "azure": { "name": "AzureOpenAI", "baseURL": "https://YOUR_RESOURCE_NAME.openai.azure.com", // Replace with your Azure endpoint "envKey": "AZURE_OPENAI_API_KEY" } }, "provider": "azure", // Set Azure as the active provider "model": "o4-mini" // Use your Azure deployment name here // ... other config settings } ``` 2. **Set up Environment Variables:** ```bash # Set the API Key for your Azure OpenAI resource export AZURE_OPENAI_API_KEY="your-azure-api-key-here" # Set the API Version (Optional - defaults to `2025-03-01-preview` if not set) # Ensure this version is supported by your Azure deployment and endpoint export AZURE_OPENAI_API_VERSION="2025-03-01-preview" ``` 3. **Get the Codex CLI by building from this PR branch:** Clone your fork, checkout this branch (`feat/azure-openai`), navigate to `codex-cli`, and build: ```bash # cd /path/to/your/fork/codex git checkout feat/azure-openai # Or your branch name cd codex-cli corepack enable pnpm install pnpm build ``` 4. **Invoke Codex:** Run the locally built CLI using `node` from the `codex-cli` directory: ```bash node ./dist/cli.js "Explain the purpose of this PR" ``` *(Alternatively, if you ran `pnpm link` after building, you can use `codex "Explain the purpose of this PR"` from anywhere)*. 5. **Verify:** Confirm that the command executes successfully and interacts with your configured Azure OpenAI deployment. --- ## Tests - [x] Tested locally against an Azure OpenAI deployment using API Key authentication. Basic commands and interactions confirmed working. --- ## Checklist - [x] Added Azure provider details to configuration files (`providers.ts`, `config.ts`). - [x] Implemented conditional `AzureOpenAI` client initialization based on provider setting. - [x] Ensured `apiVersion` is passed correctly to the Azure client. - [x] Updated `README.md` with Azure OpenAI setup instructions. - [x] Manually tested core functionality against a live Azure OpenAI endpoint. - [x] Add/update automated tests for the Azure code path (pending `main` stability). cc @theabhinavdas @nikodem-wrona @fouad-openai @tibo-openai (adjust as needed) --- I have read the CLA Document and I hereby sign the CLA
2025-05-09 18:11:32 -07:00
const oai = createOpenAIClient(config);
feat: shell command explanation option (#173) # Shell Command Explanation Option ## Description This PR adds an option to explain shell commands when the user is prompted to approve them (Fixes #110). When reviewing a shell command, users can now select "Explain this command" to get a detailed explanation of what the command does before deciding whether to approve or reject it. ## Changes - Added a new "EXPLAIN" option to the `ReviewDecision` enum - Updated the command review UI to include an "Explain this command (x)" option - Implemented the logic to send the command to the LLM for explanation using the same model as the agent - Added a display for the explanation in the command review UI - Updated all relevant components to pass the explanation through the component tree ## Benefits - Improves user understanding of shell commands before approving them - Reduces the risk of approving potentially harmful commands - Enhances the educational aspect of the tool, helping users learn about shell commands - Maintains the same workflow with minimal UI changes ## Testing - Manually tested the explanation feature with various shell commands - Verified that the explanation is displayed correctly in the UI - Confirmed that the user can still approve or reject the command after viewing the explanation ## Screenshots ![improved_shell_explanation_demo](https://github.com/user-attachments/assets/05923481-29db-4eba-9cc6-5e92301d2be0) ## Additional Notes The explanation is generated using the same model as the agent, ensuring consistency in the quality and style of explanations. --------- Signed-off-by: crazywolf132 <crazywolf132@gmail.com>
2025-04-18 06:28:58 +10:00
// Format the command for display
const commandForDisplay = formatCommandForDisplay(command);
// Create a prompt that asks for an explanation with a more detailed system prompt
const response = await oai.chat.completions.create({
model,
...(flexMode ? { service_tier: "flex" } : {}),
feat: shell command explanation option (#173) # Shell Command Explanation Option ## Description This PR adds an option to explain shell commands when the user is prompted to approve them (Fixes #110). When reviewing a shell command, users can now select "Explain this command" to get a detailed explanation of what the command does before deciding whether to approve or reject it. ## Changes - Added a new "EXPLAIN" option to the `ReviewDecision` enum - Updated the command review UI to include an "Explain this command (x)" option - Implemented the logic to send the command to the LLM for explanation using the same model as the agent - Added a display for the explanation in the command review UI - Updated all relevant components to pass the explanation through the component tree ## Benefits - Improves user understanding of shell commands before approving them - Reduces the risk of approving potentially harmful commands - Enhances the educational aspect of the tool, helping users learn about shell commands - Maintains the same workflow with minimal UI changes ## Testing - Manually tested the explanation feature with various shell commands - Verified that the explanation is displayed correctly in the UI - Confirmed that the user can still approve or reject the command after viewing the explanation ## Screenshots ![improved_shell_explanation_demo](https://github.com/user-attachments/assets/05923481-29db-4eba-9cc6-5e92301d2be0) ## Additional Notes The explanation is generated using the same model as the agent, ensuring consistency in the quality and style of explanations. --------- Signed-off-by: crazywolf132 <crazywolf132@gmail.com>
2025-04-18 06:28:58 +10:00
messages: [
{
role: "system",
content:
"You are an expert in shell commands and terminal operations. Your task is to provide detailed, accurate explanations of shell commands that users are considering executing. Break down each part of the command, explain what it does, identify any potential risks or side effects, and explain why someone might want to run it. Be specific about what files or systems will be affected. If the command could potentially be harmful, make sure to clearly highlight those risks.",
},
{
role: "user",
content: `Please explain this shell command in detail: \`${commandForDisplay}\`\n\nProvide a structured explanation that includes:\n1. A brief overview of what the command does\n2. A breakdown of each part of the command (flags, arguments, etc.)\n3. What files, directories, or systems will be affected\n4. Any potential risks or side effects\n5. Why someone might want to run this command\n\nBe specific and technical - this explanation will help the user decide whether to approve or reject the command.`,
},
],
});
// Extract the explanation from the response
const explanation =
response.choices[0]?.message.content || "Unable to generate explanation.";
return explanation;
} catch (error) {
log(`Error generating command explanation: ${error}`);
let errorMessage = "Unable to generate explanation due to an error.";
if (error instanceof Error) {
errorMessage = `Unable to generate explanation: ${error.message}`;
// If it's an API error, check for more specific information
if ("status" in error && typeof error.status === "number") {
// Handle API-specific errors
if (error.status === 401) {
errorMessage =
"Unable to generate explanation: API key is invalid or expired.";
} else if (error.status === 429) {
errorMessage =
"Unable to generate explanation: Rate limit exceeded. Please try again later.";
} else if (error.status >= 500) {
errorMessage =
"Unable to generate explanation: OpenAI service is currently unavailable. Please try again later.";
}
}
}
return errorMessage;
}
}
export default function TerminalChat({
config,
prompt: _initialPrompt,
imagePaths: _initialImagePaths,
approvalPolicy: initialApprovalPolicy,
additionalWritableRoots,
fullStdout,
}: Props): React.ReactElement {
const notify = Boolean(config.notify);
const [model, setModel] = useState<string>(config.model);
const [provider, setProvider] = useState<string>(config.provider || "openai");
const [lastResponseId, setLastResponseId] = useState<string | null>(null);
const [items, setItems] = useState<Array<ResponseItem>>([]);
const [loading, setLoading] = useState<boolean>(false);
const [approvalPolicy, setApprovalPolicy] = useState<ApprovalPolicy>(
initialApprovalPolicy,
);
const [thinkingSeconds, setThinkingSeconds] = useState(0);
const handleCompact = async () => {
setLoading(true);
try {
const summary = await generateCompactSummary(
items,
model,
Boolean(config.flexMode),
config,
);
setItems([
{
id: `compact-${Date.now()}`,
type: "message",
role: "assistant",
content: [{ type: "output_text", text: summary }],
} as ResponseItem,
]);
} catch (err) {
setItems((prev) => [
...prev,
{
id: `compact-error-${Date.now()}`,
type: "message",
role: "system",
content: [
{ type: "input_text", text: `Failed to compact context: ${err}` },
],
} as ResponseItem,
]);
} finally {
setLoading(false);
}
};
feat: shell command explanation option (#173) # Shell Command Explanation Option ## Description This PR adds an option to explain shell commands when the user is prompted to approve them (Fixes #110). When reviewing a shell command, users can now select "Explain this command" to get a detailed explanation of what the command does before deciding whether to approve or reject it. ## Changes - Added a new "EXPLAIN" option to the `ReviewDecision` enum - Updated the command review UI to include an "Explain this command (x)" option - Implemented the logic to send the command to the LLM for explanation using the same model as the agent - Added a display for the explanation in the command review UI - Updated all relevant components to pass the explanation through the component tree ## Benefits - Improves user understanding of shell commands before approving them - Reduces the risk of approving potentially harmful commands - Enhances the educational aspect of the tool, helping users learn about shell commands - Maintains the same workflow with minimal UI changes ## Testing - Manually tested the explanation feature with various shell commands - Verified that the explanation is displayed correctly in the UI - Confirmed that the user can still approve or reject the command after viewing the explanation ## Screenshots ![improved_shell_explanation_demo](https://github.com/user-attachments/assets/05923481-29db-4eba-9cc6-5e92301d2be0) ## Additional Notes The explanation is generated using the same model as the agent, ensuring consistency in the quality and style of explanations. --------- Signed-off-by: crazywolf132 <crazywolf132@gmail.com>
2025-04-18 06:28:58 +10:00
const {
requestConfirmation,
confirmationPrompt,
explanation,
submitConfirmation,
} = useConfirmation();
const [overlayMode, setOverlayMode] = useState<OverlayModeType>("none");
// Store the diff text when opening the diff overlay so the view isnt
// recomputed on every rerender while it is open.
// diffText is passed down to the DiffOverlay component. The setter is
// currently unused but retained for potential future updates. Prefix with
// an underscore so eslint ignores the unused variable.
const [diffText, _setDiffText] = useState<string>("");
const [initialPrompt, setInitialPrompt] = useState(_initialPrompt);
const [initialImagePaths, setInitialImagePaths] =
useState(_initialImagePaths);
const PWD = React.useMemo(() => shortCwd(), []);
// Keep a single AgentLoop instance alive across renders;
// recreate only when model/instructions/approvalPolicy change.
const agentRef = React.useRef<AgentLoop>();
const [, forceUpdate] = React.useReducer((c) => c + 1, 0); // trigger rerender
// ────────────────────────────────────────────────────────────────
// DEBUG: log every render w/ key bits of state
// ────────────────────────────────────────────────────────────────
log(
`render - agent? ${Boolean(agentRef.current)} loading=${loading} items=${
items.length
}`,
);
useEffect(() => {
// Skip recreating the agent if awaiting a decision on a pending confirmation.
feat: allow switching approval modes when prompted to approve an edit/command (#400) Implements https://github.com/openai/codex/issues/392 When the user is in suggest or auto-edit mode and gets an approval request, they now have an option in the `Shell Command` dialog to: `Switch approval mode (v)` That option brings up the standard `Switch approval mode` dialog, allowing the user to switch into the desired mode, then drops them back to the `Shell Command` dialog's `Allow command?` prompt, allowing them to approve the current command and let the agent continue doing the rest of what it was doing without interruption. ``` ╭──────────────────────────────────────────────────────── │Shell Command │ │$ apply_patch << 'PATCH' │*** Begin Patch │*** Update File: foo.txt │@@ -1 +1 @@ │-foo │+bar │*** End Patch │PATCH │ │ │Allow command? │ │ Yes (y) │ Explain this command (x) │ Edit or give feedback (e) │ Switch approval mode (v) │ No, and keep going (n) │ No, and stop for now (esc) ╰────────────────────────────────────────────────────────╭──────────────────────────────────────────────────────── │ Switch approval mode │ Current mode: suggest │ │ │ │ ❯ suggest │ auto-edit │ full-auto │ type to search · enter to confirm · esc to cancel ╰──────────────────────────────────────────────────────── ```
2025-04-19 07:21:19 -07:00
if (confirmationPrompt != null) {
log("skip AgentLoop recreation due to pending confirmationPrompt");
feat: allow switching approval modes when prompted to approve an edit/command (#400) Implements https://github.com/openai/codex/issues/392 When the user is in suggest or auto-edit mode and gets an approval request, they now have an option in the `Shell Command` dialog to: `Switch approval mode (v)` That option brings up the standard `Switch approval mode` dialog, allowing the user to switch into the desired mode, then drops them back to the `Shell Command` dialog's `Allow command?` prompt, allowing them to approve the current command and let the agent continue doing the rest of what it was doing without interruption. ``` ╭──────────────────────────────────────────────────────── │Shell Command │ │$ apply_patch << 'PATCH' │*** Begin Patch │*** Update File: foo.txt │@@ -1 +1 @@ │-foo │+bar │*** End Patch │PATCH │ │ │Allow command? │ │ Yes (y) │ Explain this command (x) │ Edit or give feedback (e) │ Switch approval mode (v) │ No, and keep going (n) │ No, and stop for now (esc) ╰────────────────────────────────────────────────────────╭──────────────────────────────────────────────────────── │ Switch approval mode │ Current mode: suggest │ │ │ │ ❯ suggest │ auto-edit │ full-auto │ type to search · enter to confirm · esc to cancel ╰──────────────────────────────────────────────────────── ```
2025-04-19 07:21:19 -07:00
return;
}
log("creating NEW AgentLoop");
log(
`model=${model} provider=${provider} instructions=${Boolean(
config.instructions,
)} approvalPolicy=${approvalPolicy}`,
);
// Tear down any existing loop before creating a new one.
agentRef.current?.terminate();
const sessionId = crypto.randomUUID();
agentRef.current = new AgentLoop({
model,
provider,
config,
instructions: config.instructions,
approvalPolicy,
disableResponseStorage: config.disableResponseStorage,
additionalWritableRoots,
onLastResponseId: setLastResponseId,
onItem: (item) => {
log(`onItem: ${JSON.stringify(item)}`);
setItems((prev) => {
const updated = uniqueById([...prev, item as ResponseItem]);
saveRollout(sessionId, updated);
return updated;
});
},
onLoading: setLoading,
getCommandConfirmation: async (
command: Array<string>,
applyPatch: ApplyPatchCommand | undefined,
): Promise<CommandConfirmation> => {
log(`getCommandConfirmation: ${command}`);
const commandForDisplay = formatCommandForDisplay(command);
feat: shell command explanation option (#173) # Shell Command Explanation Option ## Description This PR adds an option to explain shell commands when the user is prompted to approve them (Fixes #110). When reviewing a shell command, users can now select "Explain this command" to get a detailed explanation of what the command does before deciding whether to approve or reject it. ## Changes - Added a new "EXPLAIN" option to the `ReviewDecision` enum - Updated the command review UI to include an "Explain this command (x)" option - Implemented the logic to send the command to the LLM for explanation using the same model as the agent - Added a display for the explanation in the command review UI - Updated all relevant components to pass the explanation through the component tree ## Benefits - Improves user understanding of shell commands before approving them - Reduces the risk of approving potentially harmful commands - Enhances the educational aspect of the tool, helping users learn about shell commands - Maintains the same workflow with minimal UI changes ## Testing - Manually tested the explanation feature with various shell commands - Verified that the explanation is displayed correctly in the UI - Confirmed that the user can still approve or reject the command after viewing the explanation ## Screenshots ![improved_shell_explanation_demo](https://github.com/user-attachments/assets/05923481-29db-4eba-9cc6-5e92301d2be0) ## Additional Notes The explanation is generated using the same model as the agent, ensuring consistency in the quality and style of explanations. --------- Signed-off-by: crazywolf132 <crazywolf132@gmail.com>
2025-04-18 06:28:58 +10:00
// First request for confirmation
let { decision: review, customDenyMessage } = await requestConfirmation(
<TerminalChatToolCallCommand commandForDisplay={commandForDisplay} />,
);
// If the user wants an explanation, generate one and ask again.
feat: shell command explanation option (#173) # Shell Command Explanation Option ## Description This PR adds an option to explain shell commands when the user is prompted to approve them (Fixes #110). When reviewing a shell command, users can now select "Explain this command" to get a detailed explanation of what the command does before deciding whether to approve or reject it. ## Changes - Added a new "EXPLAIN" option to the `ReviewDecision` enum - Updated the command review UI to include an "Explain this command (x)" option - Implemented the logic to send the command to the LLM for explanation using the same model as the agent - Added a display for the explanation in the command review UI - Updated all relevant components to pass the explanation through the component tree ## Benefits - Improves user understanding of shell commands before approving them - Reduces the risk of approving potentially harmful commands - Enhances the educational aspect of the tool, helping users learn about shell commands - Maintains the same workflow with minimal UI changes ## Testing - Manually tested the explanation feature with various shell commands - Verified that the explanation is displayed correctly in the UI - Confirmed that the user can still approve or reject the command after viewing the explanation ## Screenshots ![improved_shell_explanation_demo](https://github.com/user-attachments/assets/05923481-29db-4eba-9cc6-5e92301d2be0) ## Additional Notes The explanation is generated using the same model as the agent, ensuring consistency in the quality and style of explanations. --------- Signed-off-by: crazywolf132 <crazywolf132@gmail.com>
2025-04-18 06:28:58 +10:00
if (review === ReviewDecision.EXPLAIN) {
log(`Generating explanation for command: ${commandForDisplay}`);
const explanation = await generateCommandExplanation(
command,
model,
Boolean(config.flexMode),
config,
);
feat: shell command explanation option (#173) # Shell Command Explanation Option ## Description This PR adds an option to explain shell commands when the user is prompted to approve them (Fixes #110). When reviewing a shell command, users can now select "Explain this command" to get a detailed explanation of what the command does before deciding whether to approve or reject it. ## Changes - Added a new "EXPLAIN" option to the `ReviewDecision` enum - Updated the command review UI to include an "Explain this command (x)" option - Implemented the logic to send the command to the LLM for explanation using the same model as the agent - Added a display for the explanation in the command review UI - Updated all relevant components to pass the explanation through the component tree ## Benefits - Improves user understanding of shell commands before approving them - Reduces the risk of approving potentially harmful commands - Enhances the educational aspect of the tool, helping users learn about shell commands - Maintains the same workflow with minimal UI changes ## Testing - Manually tested the explanation feature with various shell commands - Verified that the explanation is displayed correctly in the UI - Confirmed that the user can still approve or reject the command after viewing the explanation ## Screenshots ![improved_shell_explanation_demo](https://github.com/user-attachments/assets/05923481-29db-4eba-9cc6-5e92301d2be0) ## Additional Notes The explanation is generated using the same model as the agent, ensuring consistency in the quality and style of explanations. --------- Signed-off-by: crazywolf132 <crazywolf132@gmail.com>
2025-04-18 06:28:58 +10:00
log(`Generated explanation: ${explanation}`);
// Ask for confirmation again, but with the explanation.
feat: shell command explanation option (#173) # Shell Command Explanation Option ## Description This PR adds an option to explain shell commands when the user is prompted to approve them (Fixes #110). When reviewing a shell command, users can now select "Explain this command" to get a detailed explanation of what the command does before deciding whether to approve or reject it. ## Changes - Added a new "EXPLAIN" option to the `ReviewDecision` enum - Updated the command review UI to include an "Explain this command (x)" option - Implemented the logic to send the command to the LLM for explanation using the same model as the agent - Added a display for the explanation in the command review UI - Updated all relevant components to pass the explanation through the component tree ## Benefits - Improves user understanding of shell commands before approving them - Reduces the risk of approving potentially harmful commands - Enhances the educational aspect of the tool, helping users learn about shell commands - Maintains the same workflow with minimal UI changes ## Testing - Manually tested the explanation feature with various shell commands - Verified that the explanation is displayed correctly in the UI - Confirmed that the user can still approve or reject the command after viewing the explanation ## Screenshots ![improved_shell_explanation_demo](https://github.com/user-attachments/assets/05923481-29db-4eba-9cc6-5e92301d2be0) ## Additional Notes The explanation is generated using the same model as the agent, ensuring consistency in the quality and style of explanations. --------- Signed-off-by: crazywolf132 <crazywolf132@gmail.com>
2025-04-18 06:28:58 +10:00
const confirmResult = await requestConfirmation(
<TerminalChatToolCallCommand
commandForDisplay={commandForDisplay}
feat: shell command explanation option (#173) # Shell Command Explanation Option ## Description This PR adds an option to explain shell commands when the user is prompted to approve them (Fixes #110). When reviewing a shell command, users can now select "Explain this command" to get a detailed explanation of what the command does before deciding whether to approve or reject it. ## Changes - Added a new "EXPLAIN" option to the `ReviewDecision` enum - Updated the command review UI to include an "Explain this command (x)" option - Implemented the logic to send the command to the LLM for explanation using the same model as the agent - Added a display for the explanation in the command review UI - Updated all relevant components to pass the explanation through the component tree ## Benefits - Improves user understanding of shell commands before approving them - Reduces the risk of approving potentially harmful commands - Enhances the educational aspect of the tool, helping users learn about shell commands - Maintains the same workflow with minimal UI changes ## Testing - Manually tested the explanation feature with various shell commands - Verified that the explanation is displayed correctly in the UI - Confirmed that the user can still approve or reject the command after viewing the explanation ## Screenshots ![improved_shell_explanation_demo](https://github.com/user-attachments/assets/05923481-29db-4eba-9cc6-5e92301d2be0) ## Additional Notes The explanation is generated using the same model as the agent, ensuring consistency in the quality and style of explanations. --------- Signed-off-by: crazywolf132 <crazywolf132@gmail.com>
2025-04-18 06:28:58 +10:00
explanation={explanation}
/>,
);
feat: shell command explanation option (#173) # Shell Command Explanation Option ## Description This PR adds an option to explain shell commands when the user is prompted to approve them (Fixes #110). When reviewing a shell command, users can now select "Explain this command" to get a detailed explanation of what the command does before deciding whether to approve or reject it. ## Changes - Added a new "EXPLAIN" option to the `ReviewDecision` enum - Updated the command review UI to include an "Explain this command (x)" option - Implemented the logic to send the command to the LLM for explanation using the same model as the agent - Added a display for the explanation in the command review UI - Updated all relevant components to pass the explanation through the component tree ## Benefits - Improves user understanding of shell commands before approving them - Reduces the risk of approving potentially harmful commands - Enhances the educational aspect of the tool, helping users learn about shell commands - Maintains the same workflow with minimal UI changes ## Testing - Manually tested the explanation feature with various shell commands - Verified that the explanation is displayed correctly in the UI - Confirmed that the user can still approve or reject the command after viewing the explanation ## Screenshots ![improved_shell_explanation_demo](https://github.com/user-attachments/assets/05923481-29db-4eba-9cc6-5e92301d2be0) ## Additional Notes The explanation is generated using the same model as the agent, ensuring consistency in the quality and style of explanations. --------- Signed-off-by: crazywolf132 <crazywolf132@gmail.com>
2025-04-18 06:28:58 +10:00
// Update the decision based on the second confirmation.
feat: shell command explanation option (#173) # Shell Command Explanation Option ## Description This PR adds an option to explain shell commands when the user is prompted to approve them (Fixes #110). When reviewing a shell command, users can now select "Explain this command" to get a detailed explanation of what the command does before deciding whether to approve or reject it. ## Changes - Added a new "EXPLAIN" option to the `ReviewDecision` enum - Updated the command review UI to include an "Explain this command (x)" option - Implemented the logic to send the command to the LLM for explanation using the same model as the agent - Added a display for the explanation in the command review UI - Updated all relevant components to pass the explanation through the component tree ## Benefits - Improves user understanding of shell commands before approving them - Reduces the risk of approving potentially harmful commands - Enhances the educational aspect of the tool, helping users learn about shell commands - Maintains the same workflow with minimal UI changes ## Testing - Manually tested the explanation feature with various shell commands - Verified that the explanation is displayed correctly in the UI - Confirmed that the user can still approve or reject the command after viewing the explanation ## Screenshots ![improved_shell_explanation_demo](https://github.com/user-attachments/assets/05923481-29db-4eba-9cc6-5e92301d2be0) ## Additional Notes The explanation is generated using the same model as the agent, ensuring consistency in the quality and style of explanations. --------- Signed-off-by: crazywolf132 <crazywolf132@gmail.com>
2025-04-18 06:28:58 +10:00
review = confirmResult.decision;
customDenyMessage = confirmResult.customDenyMessage;
// Return the final decision with the explanation.
feat: shell command explanation option (#173) # Shell Command Explanation Option ## Description This PR adds an option to explain shell commands when the user is prompted to approve them (Fixes #110). When reviewing a shell command, users can now select "Explain this command" to get a detailed explanation of what the command does before deciding whether to approve or reject it. ## Changes - Added a new "EXPLAIN" option to the `ReviewDecision` enum - Updated the command review UI to include an "Explain this command (x)" option - Implemented the logic to send the command to the LLM for explanation using the same model as the agent - Added a display for the explanation in the command review UI - Updated all relevant components to pass the explanation through the component tree ## Benefits - Improves user understanding of shell commands before approving them - Reduces the risk of approving potentially harmful commands - Enhances the educational aspect of the tool, helping users learn about shell commands - Maintains the same workflow with minimal UI changes ## Testing - Manually tested the explanation feature with various shell commands - Verified that the explanation is displayed correctly in the UI - Confirmed that the user can still approve or reject the command after viewing the explanation ## Screenshots ![improved_shell_explanation_demo](https://github.com/user-attachments/assets/05923481-29db-4eba-9cc6-5e92301d2be0) ## Additional Notes The explanation is generated using the same model as the agent, ensuring consistency in the quality and style of explanations. --------- Signed-off-by: crazywolf132 <crazywolf132@gmail.com>
2025-04-18 06:28:58 +10:00
return { review, customDenyMessage, applyPatch, explanation };
}
return { review, customDenyMessage, applyPatch };
},
});
// Force a render so JSX below can "see" the freshly created agent.
forceUpdate();
log(`AgentLoop created: ${inspect(agentRef.current, { depth: 1 })}`);
return () => {
log("terminating AgentLoop");
agentRef.current?.terminate();
agentRef.current = undefined;
forceUpdate(); // rerender after teardown too
};
// We intentionally omit 'approvalPolicy' and 'confirmationPrompt' from the deps
// so switching modes or showing confirmation dialogs doesnt tear down the loop.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [model, provider, config, requestConfirmation, additionalWritableRoots]);
// Whenever loading starts/stops, reset or start a timer — but pause the
// timer while a confirmation overlay is displayed so we don't trigger a
// rerender every second during apply_patch reviews.
useEffect(() => {
let handle: ReturnType<typeof setInterval> | null = null;
// Only tick the "thinking…" timer when the agent is actually processing
// a request *and* the user is not being asked to review a command.
if (loading && confirmationPrompt == null) {
setThinkingSeconds(0);
handle = setInterval(() => {
setThinkingSeconds((s) => s + 1);
}, 1000);
} else {
if (handle) {
clearInterval(handle);
}
setThinkingSeconds(0);
}
return () => {
if (handle) {
clearInterval(handle);
}
};
}, [loading, confirmationPrompt]);
// Notify desktop with a preview when an assistant response arrives.
const prevLoadingRef = useRef<boolean>(false);
useEffect(() => {
// Only notify when notifications are enabled.
if (!notify) {
prevLoadingRef.current = loading;
return;
}
if (
prevLoadingRef.current &&
!loading &&
confirmationPrompt == null &&
items.length > 0
) {
if (process.platform === "darwin") {
// find the last assistant message
const assistantMessages = items.filter(
(i) => i.type === "message" && i.role === "assistant",
);
const last = assistantMessages[assistantMessages.length - 1];
if (last) {
const text = last.content
.map((c) => {
if (c.type === "output_text") {
return c.text;
}
return "";
})
.join("")
.trim();
const preview = text.replace(/\n/g, " ").slice(0, 100);
const safePreview = preview.replace(/"/g, '\\"');
const title = "Codex CLI";
const cwd = PWD;
spawn("osascript", [
"-e",
`display notification "${safePreview}" with title "${title}" subtitle "${cwd}" sound name "Ping"`,
]);
}
}
}
prevLoadingRef.current = loading;
}, [notify, loading, confirmationPrompt, items, PWD]);
// Let's also track whenever the ref becomes available.
const agent = agentRef.current;
useEffect(() => {
log(`agentRef.current is now ${Boolean(agent)}`);
}, [agent]);
// ---------------------------------------------------------------------
// Dynamic layout constraints keep total rendered rows <= terminal rows
// ---------------------------------------------------------------------
const { rows: terminalRows } = useTerminalSize();
useEffect(() => {
const processInitialInputItems = async () => {
if (
(!initialPrompt || initialPrompt.trim() === "") &&
(!initialImagePaths || initialImagePaths.length === 0)
) {
return;
}
const inputItems = [
await createInputItem(initialPrompt || "", initialImagePaths || []),
];
// Clear them to prevent subsequent runs.
setInitialPrompt("");
setInitialImagePaths([]);
agent?.run(inputItems);
};
processInitialInputItems();
}, [agent, initialPrompt, initialImagePaths]);
// ────────────────────────────────────────────────────────────────
// In-app warning if CLI --model isn't in fetched list
// ────────────────────────────────────────────────────────────────
useEffect(() => {
(async () => {
const available = await getAvailableModels(provider);
if (model && available.length > 0 && !available.includes(model)) {
setItems((prev) => [
...prev,
{
id: `unknown-model-${Date.now()}`,
type: "message",
role: "system",
content: [
{
type: "input_text",
text: `Warning: model "${model}" is not in the list of available models for provider "${provider}".`,
},
],
},
]);
}
})();
// run once on mount
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// Just render every item in order, no grouping/collapse.
const lastMessageBatch = items.map((item) => ({ item }));
const groupCounts: Record<string, number> = {};
const userMsgCount = items.filter(
(i) => i.type === "message" && i.role === "user",
).length;
const contextLeftPercent = useMemo(
() => calculateContextPercentRemaining(items, model),
[items, model],
);
return (
<Box flexDirection="column">
<Box flexDirection="column">
{agent ? (
<TerminalMessageHistory
setOverlayMode={setOverlayMode}
batch={lastMessageBatch}
groupCounts={groupCounts}
items={items}
userMsgCount={userMsgCount}
confirmationPrompt={confirmationPrompt}
loading={loading}
thinkingSeconds={thinkingSeconds}
fullStdout={fullStdout}
headerProps={{
terminalRows,
version: CLI_VERSION,
PWD,
model,
provider,
approvalPolicy,
colorsByPolicy,
agent,
initialImagePaths,
flexModeEnabled: Boolean(config.flexMode),
}}
/>
) : (
<Box>
<Text color="gray">Initializing agent</Text>
</Box>
)}
fix: allow proper exit from new Switch approval mode dialog (#453) As described in https://github.com/openai/codex/issues/392#issuecomment-2817090022 introduced by #400 The testing I'd done worked correctly because I was using the (s) shortcut, but selecting the same option using arrow‑key → Enter on “Switch approval mode” was preventing the user from subsequently exiting the Switch approval mode dialog, requiring a ^C to quit codex entirely. With this fix, both entry methods work correctly in my testing. Per codex: Issue - When you navigated down (↓) to “Switch approval mode (s)” in the Shell Command review dialog and pressed Enter, the ApprovalModeOverlay would open—but because the underlying `TerminalChatCommandReview` component stayed mounted (albeit disabled), its own Ink input handlers immediately re‑captured the same key events and re‑opened the overlay as soon as you hit Esc or Enter again. In practice this made it impossible to exit the submenu. Root cause - We only disabled the SelectInput via `isDisabled`, but never fully unmounted the review UI when an overlay was shown, so its `useInput` and `<Select>` hooks were still active and “stealing” keys. Fix - In `terminal-chat.tsx` we now only render `<TerminalChatInput>` (and by extension `TerminalChatCommandReview`) when `overlayMode === "none"`. That unmounts all of its key handlers whenever any overlay (history, model, approval, help, diff) is open, so no input leaks through. Files changed - **src/components/chat/terminal-chat.tsx**: Wrapped the entire `<TerminalChatInput>` block in `overlayMode === "none" && agent` With that in place, arrow‑key → Enter on “Switch approval mode” correctly opens the overlay, and then you can use Enter/Esc inside the overlay without getting stuck or immediately re‑opening it.
2025-04-20 22:19:53 -07:00
{overlayMode === "none" && agent && (
<TerminalChatInput
loading={loading}
setItems={setItems}
isNew={Boolean(items.length === 0)}
setLastResponseId={setLastResponseId}
confirmationPrompt={confirmationPrompt}
feat: shell command explanation option (#173) # Shell Command Explanation Option ## Description This PR adds an option to explain shell commands when the user is prompted to approve them (Fixes #110). When reviewing a shell command, users can now select "Explain this command" to get a detailed explanation of what the command does before deciding whether to approve or reject it. ## Changes - Added a new "EXPLAIN" option to the `ReviewDecision` enum - Updated the command review UI to include an "Explain this command (x)" option - Implemented the logic to send the command to the LLM for explanation using the same model as the agent - Added a display for the explanation in the command review UI - Updated all relevant components to pass the explanation through the component tree ## Benefits - Improves user understanding of shell commands before approving them - Reduces the risk of approving potentially harmful commands - Enhances the educational aspect of the tool, helping users learn about shell commands - Maintains the same workflow with minimal UI changes ## Testing - Manually tested the explanation feature with various shell commands - Verified that the explanation is displayed correctly in the UI - Confirmed that the user can still approve or reject the command after viewing the explanation ## Screenshots ![improved_shell_explanation_demo](https://github.com/user-attachments/assets/05923481-29db-4eba-9cc6-5e92301d2be0) ## Additional Notes The explanation is generated using the same model as the agent, ensuring consistency in the quality and style of explanations. --------- Signed-off-by: crazywolf132 <crazywolf132@gmail.com>
2025-04-18 06:28:58 +10:00
explanation={explanation}
submitConfirmation={(
decision: ReviewDecision,
customDenyMessage?: string,
) =>
submitConfirmation({
decision,
customDenyMessage,
})
}
contextLeftPercent={contextLeftPercent}
openOverlay={() => setOverlayMode("history")}
openModelOverlay={() => setOverlayMode("model")}
openApprovalOverlay={() => setOverlayMode("approval")}
openHelpOverlay={() => setOverlayMode("help")}
openDiffOverlay={() => {
const { isGitRepo, diff } = getGitDiff();
let text: string;
if (isGitRepo) {
text = diff;
} else {
text = "`/diff` — _not inside a git repository_";
}
setItems((prev) => [
...prev,
{
id: `diff-${Date.now()}`,
type: "message",
role: "system",
content: [{ type: "input_text", text }],
},
]);
// Ensure no overlay is shown.
setOverlayMode("none");
}}
onCompact={handleCompact}
active={overlayMode === "none"}
interruptAgent={() => {
if (!agent) {
return;
}
log(
"TerminalChat: interruptAgent invoked calling agent.cancel()",
);
agent.cancel();
setLoading(false);
// Add a system message to indicate the interruption
setItems((prev) => [
...prev,
{
id: `interrupt-${Date.now()}`,
type: "message",
role: "system",
content: [
{
type: "input_text",
text: "⏹️ Execution interrupted by user. You can continue typing.",
},
],
},
]);
}}
submitInput={(inputs) => {
agent.run(inputs, lastResponseId || "");
return {};
}}
items={items}
thinkingSeconds={thinkingSeconds}
/>
)}
{overlayMode === "history" && (
<HistoryOverlay items={items} onExit={() => setOverlayMode("none")} />
)}
{overlayMode === "model" && (
<ModelOverlay
currentModel={model}
providers={config.providers}
currentProvider={provider}
hasLastResponse={Boolean(lastResponseId)}
onSelect={(allModels, newModel) => {
log(
"TerminalChat: interruptAgent invoked calling agent.cancel()",
);
if (!agent) {
log("TerminalChat: agent is not ready yet");
}
agent?.cancel();
setLoading(false);
if (!allModels?.includes(newModel)) {
// eslint-disable-next-line no-console
console.error(
chalk.bold.red(
`Model "${chalk.yellow(
newModel,
)}" is not available for provider "${chalk.yellow(
provider,
)}".`,
),
);
return;
}
setModel(newModel);
setLastResponseId((prev) =>
prev && newModel !== model ? null : prev,
);
// Save model to config
saveConfig({
...config,
model: newModel,
provider: provider,
});
setItems((prev) => [
...prev,
{
id: `switch-model-${Date.now()}`,
type: "message",
role: "system",
content: [
{
type: "input_text",
text: `Switched model to ${newModel}`,
},
],
},
]);
setOverlayMode("none");
}}
onSelectProvider={(newProvider) => {
log(
"TerminalChat: interruptAgent invoked calling agent.cancel()",
);
if (!agent) {
log("TerminalChat: agent is not ready yet");
}
agent?.cancel();
setLoading(false);
// Select default model for the new provider.
const defaultModel = model;
// Save provider to config.
const updatedConfig = {
...config,
provider: newProvider,
model: defaultModel,
};
saveConfig(updatedConfig);
setProvider(newProvider);
setModel(defaultModel);
setLastResponseId((prev) =>
prev && newProvider !== provider ? null : prev,
);
setItems((prev) => [
...prev,
{
id: `switch-provider-${Date.now()}`,
type: "message",
role: "system",
content: [
{
type: "input_text",
text: `Switched provider to ${newProvider} with model ${defaultModel}`,
},
],
},
]);
// Don't close the overlay so user can select a model for the new provider
// setOverlayMode("none");
}}
onExit={() => setOverlayMode("none")}
/>
)}
{overlayMode === "approval" && (
<ApprovalModeOverlay
currentMode={approvalPolicy}
onSelect={(newMode) => {
// Update approval policy without cancelling an in-progress session.
if (newMode === approvalPolicy) {
return;
}
setApprovalPolicy(newMode as ApprovalPolicy);
feat: allow switching approval modes when prompted to approve an edit/command (#400) Implements https://github.com/openai/codex/issues/392 When the user is in suggest or auto-edit mode and gets an approval request, they now have an option in the `Shell Command` dialog to: `Switch approval mode (v)` That option brings up the standard `Switch approval mode` dialog, allowing the user to switch into the desired mode, then drops them back to the `Shell Command` dialog's `Allow command?` prompt, allowing them to approve the current command and let the agent continue doing the rest of what it was doing without interruption. ``` ╭──────────────────────────────────────────────────────── │Shell Command │ │$ apply_patch << 'PATCH' │*** Begin Patch │*** Update File: foo.txt │@@ -1 +1 @@ │-foo │+bar │*** End Patch │PATCH │ │ │Allow command? │ │ Yes (y) │ Explain this command (x) │ Edit or give feedback (e) │ Switch approval mode (v) │ No, and keep going (n) │ No, and stop for now (esc) ╰────────────────────────────────────────────────────────╭──────────────────────────────────────────────────────── │ Switch approval mode │ Current mode: suggest │ │ │ │ ❯ suggest │ auto-edit │ full-auto │ type to search · enter to confirm · esc to cancel ╰──────────────────────────────────────────────────────── ```
2025-04-19 07:21:19 -07:00
if (agentRef.current) {
(
agentRef.current as unknown as {
approvalPolicy: ApprovalPolicy;
}
).approvalPolicy = newMode as ApprovalPolicy;
feat: allow switching approval modes when prompted to approve an edit/command (#400) Implements https://github.com/openai/codex/issues/392 When the user is in suggest or auto-edit mode and gets an approval request, they now have an option in the `Shell Command` dialog to: `Switch approval mode (v)` That option brings up the standard `Switch approval mode` dialog, allowing the user to switch into the desired mode, then drops them back to the `Shell Command` dialog's `Allow command?` prompt, allowing them to approve the current command and let the agent continue doing the rest of what it was doing without interruption. ``` ╭──────────────────────────────────────────────────────── │Shell Command │ │$ apply_patch << 'PATCH' │*** Begin Patch │*** Update File: foo.txt │@@ -1 +1 @@ │-foo │+bar │*** End Patch │PATCH │ │ │Allow command? │ │ Yes (y) │ Explain this command (x) │ Edit or give feedback (e) │ Switch approval mode (v) │ No, and keep going (n) │ No, and stop for now (esc) ╰────────────────────────────────────────────────────────╭──────────────────────────────────────────────────────── │ Switch approval mode │ Current mode: suggest │ │ │ │ ❯ suggest │ auto-edit │ full-auto │ type to search · enter to confirm · esc to cancel ╰──────────────────────────────────────────────────────── ```
2025-04-19 07:21:19 -07:00
}
setItems((prev) => [
...prev,
{
id: `switch-approval-${Date.now()}`,
type: "message",
role: "system",
content: [
{
type: "input_text",
text: `Switched approval mode to ${newMode}`,
},
],
},
]);
setOverlayMode("none");
}}
onExit={() => setOverlayMode("none")}
/>
)}
{overlayMode === "help" && (
<HelpOverlay onExit={() => setOverlayMode("none")} />
)}
{overlayMode === "diff" && (
<DiffOverlay
diffText={diffText}
onExit={() => setOverlayMode("none")}
/>
)}
</Box>
</Box>
);
}