mirror of
https://github.com/All-Hands-AI/OpenHands.git
synced 2026-04-29 03:00:45 -04:00
Compare commits
31 Commits
openhands-
...
rb/regen-a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4e8b7204f | ||
|
|
7f4671f2bd | ||
|
|
9939b0e826 | ||
|
|
eed2b716d1 | ||
|
|
1c8960ec68 | ||
|
|
96b7fa32fd | ||
|
|
50528ddfe3 | ||
|
|
4c13bc9ed3 | ||
|
|
b73f6bb0ea | ||
|
|
ae8f82d0ab | ||
|
|
2fc8b82500 | ||
|
|
6603ca095e | ||
|
|
a39e2574bd | ||
|
|
c2102bb925 | ||
|
|
ab14539828 | ||
|
|
714fd7c505 | ||
|
|
0322b759f2 | ||
|
|
9bb54b78db | ||
|
|
7d99e0b750 | ||
|
|
e2f07cf9ae | ||
|
|
5ad0b1ea7e | ||
|
|
74c2d8a02a | ||
|
|
026958293c | ||
|
|
0ed3ded82a | ||
|
|
a9f1a41d3d | ||
|
|
d86bf9c472 | ||
|
|
f611634dc1 | ||
|
|
26b612cde2 | ||
|
|
e8aa141287 | ||
|
|
216a378a86 | ||
|
|
8d774b6e82 |
@@ -52,12 +52,7 @@ jobs:
|
||||
- name: Build Environment
|
||||
run: make build
|
||||
- name: Regenerate integration tests
|
||||
run: |
|
||||
DEBUG=${{ inputs.debug }} \
|
||||
LOG_TO_FILE=${{ inputs.log_to_file }} \
|
||||
FORCE_REGENERATE_TESTS=${{ inputs.force_regenerate_tests }} \
|
||||
FORCE_USE_LLM=${{ inputs.force_use_llm }} \
|
||||
./tests/integration/regenerate.sh
|
||||
run: ./tests/integration/regenerate.sh
|
||||
- name: Commit changes
|
||||
run: |
|
||||
if git diff --quiet --exit-code; then
|
||||
|
||||
@@ -37,8 +37,12 @@ export function ProjectMenuCard({
|
||||
|
||||
const handlePushToGitHub = () => {
|
||||
const rawEvent = {
|
||||
content:
|
||||
"Please create a new branch and commit the changes. Then push them to the remote repository, and open up a pull request using the GitHub API and the token in the GITHUB_TOKEN environment variable",
|
||||
content: `
|
||||
Let's push the code to GitHub.
|
||||
If we're currently on the openhands-workspace branch, please create a new branch with a descriptive name.
|
||||
Commit any changes and push them to the remote repository.
|
||||
Finally, open up a pull request using the GitHub API and the token in the GITHUB_TOKEN environment variable, then show me the URL of the pull request.
|
||||
`,
|
||||
imageUrls: [],
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { FitAddon } from "@xterm/addon-fit";
|
||||
import { Terminal } from "@xterm/xterm";
|
||||
import React from "react";
|
||||
import { Command } from "#/state/commandSlice";
|
||||
import { sendTerminalCommand } from "#/services/terminalService";
|
||||
import { getTerminalCommand } from "#/services/terminalService";
|
||||
import { parseTerminalOutput } from "#/utils/parseTerminalOutput";
|
||||
import { useSocket } from "#/context/socket";
|
||||
|
||||
@@ -69,7 +69,7 @@ export const useTerminal = (commands: Command[] = []) => {
|
||||
|
||||
const handleEnter = (command: string) => {
|
||||
terminal.current?.write("\r\n");
|
||||
send(sendTerminalCommand(command));
|
||||
send(getTerminalCommand(command));
|
||||
};
|
||||
|
||||
const handleBackspace = (command: string) => {
|
||||
|
||||
@@ -167,7 +167,7 @@ export function TaskForm({ importedProjectZip, textareaRef }: TaskFormProps) {
|
||||
disabled={navigation.state === "submitting"}
|
||||
placeholder={
|
||||
selectedRepository
|
||||
? `What would you like to change in ${selectedRepository}`
|
||||
? `What would you like to change in ${selectedRepository}?`
|
||||
: "What do you want to build?"
|
||||
}
|
||||
onChange={handleChange}
|
||||
|
||||
@@ -21,8 +21,11 @@ import ActionType from "#/types/ActionType";
|
||||
import { handleAssistantMessage } from "#/services/actions";
|
||||
import { addUserMessage, clearMessages } from "#/state/chatSlice";
|
||||
import { useSocket } from "#/context/socket";
|
||||
import { sendTerminalCommand } from "#/services/terminalService";
|
||||
import { appendInput, clearTerminal } from "#/state/commandSlice";
|
||||
import {
|
||||
getGitHubTokenCommand,
|
||||
getCloneRepoCommand,
|
||||
} from "#/services/terminalService";
|
||||
import { clearTerminal } from "#/state/commandSlice";
|
||||
import { useEffectOnce } from "#/utils/use-effect-once";
|
||||
import CodeIcon from "#/assets/code.svg?react";
|
||||
import GlobeIcon from "#/assets/globe.svg?react";
|
||||
@@ -122,26 +125,6 @@ function App() {
|
||||
[],
|
||||
);
|
||||
|
||||
const exportGitHubTokenToTerminal = (gitHubToken: string) => {
|
||||
const command = `export GITHUB_TOKEN=${gitHubToken}`;
|
||||
const event = sendTerminalCommand(command);
|
||||
|
||||
send(event);
|
||||
dispatch(appendInput(command.replace(gitHubToken, "***")));
|
||||
};
|
||||
|
||||
const sendCloneRepoCommandToTerminal = (
|
||||
gitHubToken: string,
|
||||
repository: string,
|
||||
) => {
|
||||
const url = `https://${gitHubToken}@github.com/${repository}.git`;
|
||||
const command = `git clone ${url}`;
|
||||
const event = sendTerminalCommand(command);
|
||||
|
||||
send(event);
|
||||
dispatch(appendInput(command.replace(gitHubToken, "***")));
|
||||
};
|
||||
|
||||
const addIntialQueryToChat = (
|
||||
query: string,
|
||||
base64Files: string[],
|
||||
@@ -199,7 +182,7 @@ function App() {
|
||||
// handle new session
|
||||
if (!token) {
|
||||
if (ghToken && repo) {
|
||||
sendCloneRepoCommandToTerminal(ghToken, repo);
|
||||
send(getCloneRepoCommand(ghToken, repo));
|
||||
dispatch(clearSelectedRepository()); // reset selected repository; maybe better to move this to '/'?
|
||||
}
|
||||
|
||||
@@ -232,7 +215,7 @@ function App() {
|
||||
React.useEffect(() => {
|
||||
// Export if the user valid, this could happen mid-session so it is handled here
|
||||
if (userId && ghToken && runtimeActive) {
|
||||
exportGitHubTokenToTerminal(ghToken);
|
||||
send(getGitHubTokenCommand(ghToken));
|
||||
}
|
||||
}, [userId, ghToken, runtimeActive]);
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ const messageActions = {
|
||||
store.dispatch(addAssistantMessage(message.message));
|
||||
},
|
||||
[ActionType.RUN]: (message: ActionMessage) => {
|
||||
if (message.args.hidden) return;
|
||||
if (message.args.thought) {
|
||||
store.dispatch(addAssistantMessage(message.args.thought));
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { addAssistantMessage } from "#/state/chatSlice";
|
||||
export function handleObservationMessage(message: ObservationMessage) {
|
||||
switch (message.observation) {
|
||||
case ObservationType.RUN:
|
||||
if (message.extras.hidden) break;
|
||||
store.dispatch(appendOutput(message.content));
|
||||
break;
|
||||
case ObservationType.RUN_IPYTHON:
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
import ActionType from "#/types/ActionType";
|
||||
|
||||
export function sendTerminalCommand(command: string) {
|
||||
const event = { action: ActionType.RUN, args: { command } };
|
||||
export function getTerminalCommand(command: string, hidden: boolean = false) {
|
||||
const event = { action: ActionType.RUN, args: { command, hidden } };
|
||||
return JSON.stringify(event);
|
||||
}
|
||||
|
||||
export function getGitHubTokenCommand(gitHubToken: string) {
|
||||
const command = `export GITHUB_TOKEN=${gitHubToken}`;
|
||||
const event = getTerminalCommand(command, true);
|
||||
return event;
|
||||
}
|
||||
|
||||
export function getCloneRepoCommand(gitHubToken: string, repository: string) {
|
||||
const url = `https://${gitHubToken}@github.com/${repository}.git`;
|
||||
const dirName = repository.split("/")[1];
|
||||
const command = `git clone ${url} ${dirName} ; cd ${dirName} ; git checkout -b openhands-workspace`;
|
||||
const event = getTerminalCommand(command, true);
|
||||
return event;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ export interface CommandAction extends OpenHandsActionEvent<"run"> {
|
||||
command: string;
|
||||
is_confirmed: "confirmed" | "rejected" | "awaiting_confirmation";
|
||||
thought: string;
|
||||
hidden?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface CommandObservation extends OpenHandsObservationEvent<"run"> {
|
||||
command: string;
|
||||
command_id: number;
|
||||
exit_code: number;
|
||||
hidden?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -174,6 +174,8 @@ class AgentController:
|
||||
Args:
|
||||
event (Event): The incoming event to process.
|
||||
"""
|
||||
if hasattr(event, 'hidden') and event.hidden:
|
||||
return
|
||||
if isinstance(event, Action):
|
||||
await self._handle_action(event)
|
||||
elif isinstance(event, Observation):
|
||||
|
||||
@@ -25,6 +25,7 @@ class CmdRunAction(Action):
|
||||
# file2.txt
|
||||
# root@sandbox:~# <-- this is the command prompt
|
||||
|
||||
hidden: bool = False
|
||||
action: str = ActionType.RUN
|
||||
runnable: ClassVar[bool] = True
|
||||
is_confirmed: ActionConfirmationStatus = ActionConfirmationStatus.CONFIRMED
|
||||
|
||||
@@ -11,6 +11,7 @@ class CmdOutputObservation(Observation):
|
||||
command_id: int
|
||||
command: str
|
||||
exit_code: int = 0
|
||||
hidden: bool = False
|
||||
observation: str = ObservationType.RUN
|
||||
|
||||
@property
|
||||
|
||||
@@ -49,7 +49,10 @@ class ShortTermHistory(list[Event]):
|
||||
return list(self.get_events(include_delegates=include_delegates))
|
||||
|
||||
def get_events(
|
||||
self, reverse: bool = False, include_delegates: bool = False
|
||||
self,
|
||||
reverse: bool = False,
|
||||
include_delegates: bool = False,
|
||||
include_hidden=False,
|
||||
) -> Iterable[Event]:
|
||||
"""Return the events as a stream of Event objects."""
|
||||
# TODO handle AgentRejectAction, if it's not part of a chunk ending with an AgentDelegateObservation
|
||||
@@ -69,6 +72,8 @@ class ShortTermHistory(list[Event]):
|
||||
reverse=reverse,
|
||||
filter_out_type=self.filter_out,
|
||||
):
|
||||
if not include_hidden and hasattr(event, 'hidden') and event.hidden:
|
||||
continue
|
||||
# TODO add summaries
|
||||
# and filter out events that were included in a summary
|
||||
|
||||
|
||||
@@ -466,6 +466,7 @@ class RuntimeClient:
|
||||
command_id=-1,
|
||||
content=all_output.rstrip('\r\n'),
|
||||
command=action.command,
|
||||
hidden=action.hidden,
|
||||
exit_code=exit_code,
|
||||
)
|
||||
except UnicodeDecodeError:
|
||||
|
||||
@@ -102,6 +102,7 @@ def test_cmd_run_action_serialization_deserialization():
|
||||
'command': 'echo "Hello world"',
|
||||
'thought': '',
|
||||
'keep_prompt': True,
|
||||
'hidden': False,
|
||||
'is_confirmed': ActionConfirmationStatus.CONFIRMED,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -47,7 +47,12 @@ def test_observation_event_props_serialization_deserialization():
|
||||
'timestamp': '2021-08-01T12:00:00',
|
||||
'observation': 'run',
|
||||
'message': 'Command `ls -l` executed with exit code 0.',
|
||||
'extras': {'exit_code': 0, 'command': 'ls -l', 'command_id': 3},
|
||||
'extras': {
|
||||
'exit_code': 0,
|
||||
'command': 'ls -l',
|
||||
'command_id': 3,
|
||||
'hidden': False,
|
||||
},
|
||||
'content': 'foo.txt',
|
||||
}
|
||||
serialization_deserialization(original_observation_dict, CmdOutputObservation)
|
||||
@@ -56,7 +61,12 @@ def test_observation_event_props_serialization_deserialization():
|
||||
def test_command_output_observation_serialization_deserialization():
|
||||
original_observation_dict = {
|
||||
'observation': 'run',
|
||||
'extras': {'exit_code': 0, 'command': 'ls -l', 'command_id': 3},
|
||||
'extras': {
|
||||
'exit_code': 0,
|
||||
'command': 'ls -l',
|
||||
'command_id': 3,
|
||||
'hidden': False,
|
||||
},
|
||||
'message': 'Command `ls -l` executed with exit code 0.',
|
||||
'content': 'foo.txt',
|
||||
}
|
||||
|
||||
@@ -220,6 +220,7 @@ def test_unsafe_bash_command(temp_dir: str):
|
||||
arguments={
|
||||
'blocking': False,
|
||||
'command': 'ls',
|
||||
'hidden': False,
|
||||
'keep_prompt': True,
|
||||
'is_confirmed': ActionConfirmationStatus.CONFIRMED,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user