Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Process interactive commands and stream output in logs #2059

Closed
wants to merge 10 commits into from

Conversation

SmartManoj
Copy link
Contributor

Solves #577 and also streaming output to logs only #1625 (comment)

image

@@ -738,21 +769,21 @@ def close(self):
except Exception as e:
logger.exception('Failed to start Docker container: %s', e)
sys.exit(1)

logger.setLevel('DEBUG')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forget to delete or intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

intentional; as it is for devs

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am strongly against changing logger level in the code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is in the main block only.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is in the main block only.

Ah I see, that's much less concerning then... I still prefer we don't do it in the code, coz it might surprise developers

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe logging about the change would help?

Comment on lines 46 to +51
_exit_code = self.ssh.before.strip()
return int(_exit_code)
try:
return int(_exit_code)
except ValueError:
logger.error(f'Invalid exit code: {_exit_code}')
return -1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to check the error rather than use try catch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got Jupyter kernel ready in _exit_code and the program stopped when I set timeout to 3 for testing. There some bugs in that like #1915. Also, it is handled in https://github.com/OpenDevin/OpenDevin/blob/d8d17aae03c8c0987cbce625103cd15020fb05da/opendevin/runtime/plugins/mixin.py#L55-L58

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CC: @neubig, I am waiting for the reply.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree with @yufansong that we should fix the underlying problem, rather than catching the error here.

@@ -738,21 +769,21 @@ def close(self):
except Exception as e:
logger.exception('Failed to start Docker container: %s', e)
sys.exit(1)

logger.setLevel('DEBUG')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am strongly against changing logger level in the code

Copy link
Collaborator

@yufansong yufansong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some code need to be refactor.

@neubig
Copy link
Contributor

neubig commented May 31, 2024

@SmartManoj : if this is ready for review again, could you re-request review? You can do it by clicking the "cycle" button next to the reviewers' names.

@SmartManoj SmartManoj requested review from yufansong and li-boxuan May 31, 2024 23:09
@SmartManoj SmartManoj dismissed li-boxuan’s stale review June 1, 2024 06:50

reverted to old stated.

@li-boxuan
Copy link
Collaborator

I don't understand what problem this PR is trying to solve, and how it is solved. Do you mind elaborating more?

@SmartManoj
Copy link
Contributor Author

Solves #577

It will parse the output and if it requires "yes" confirmation from the user, it will send that.

@SmartManoj SmartManoj changed the title Allowed interactive commands Processed interactive commands Jun 1, 2024
Comment on lines +462 to +493
prompts = [
r'Do you want to continue\? \[Y/n\]',
self.ssh.PROMPT,
EOF,
TIMEOUT,
]
command_output = ''
timeout_counter = 0
while True:
try:
# Wait for one of the prompts
index = self.ssh.expect(prompts, timeout=1)
line = self.ssh.before
logger.info(line)
command_output += line
if index == 0:
self.ssh.sendline('Y')
elif index == 1:
break
elif index == 2:
logger.debug('End of file')
break
elif index == 3:
timeout_counter += 1
if timeout_counter > timeout:
logger.exception(
'Command timed out, killing process...', exc_info=False
)
return self._send_interrupt(cmd)
except ExceptionPexpect as e:
logger.exception(f'Unexpected exception: {e}')
break
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems brittle to me. Auto-confirm based on prompt text is kind of a hack

It looks like you have another PR which warns the agent about commands like this...will that suffice?

I'm generally concerned that this file is filling up with little hacks for the agent, instead of just being a thin wrapper around SSH.

Copy link
Contributor Author

@SmartManoj SmartManoj Jun 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean #2034 (I'm not the author)? We can warn them but they are not AGI models yet to follow that always. So need some little tweaks. Also helps weaker LLMs

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is introducing several changes in the way that prompts are handled.

  1. Automatic entering of "Y" -- I think this is a bad idea... Usually a confirmation dialog is there because you need to check before doing something dangerous, and having the system automatically choose to proceed seems dangerous.
  2. This does nothing, so it can probably just be removed?
  3. Adding "end of file" may be good, but what was the behavior before?
  4. This seems like a good idea, and I actually like it better than the solution in fix: codeact bug [If running a command that never returns, it gets stuck #1895] #2034, which expands the prompt for something that can probably be done automatically like we do it here.

@SmartManoj SmartManoj changed the title Processed interactive commands Processed interactive commands and stream able output in logs Jun 4, 2024
@SmartManoj SmartManoj changed the title Processed interactive commands and stream able output in logs Processed interactive commands and stream-able output in logs Jun 5, 2024
@SmartManoj SmartManoj changed the title Processed interactive commands and stream-able output in logs Processed interactive commands and streamable output in logs Jun 5, 2024
Copy link
Contributor

@neubig neubig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this! I had a few comments.

Comment on lines +462 to +493
prompts = [
r'Do you want to continue\? \[Y/n\]',
self.ssh.PROMPT,
EOF,
TIMEOUT,
]
command_output = ''
timeout_counter = 0
while True:
try:
# Wait for one of the prompts
index = self.ssh.expect(prompts, timeout=1)
line = self.ssh.before
logger.info(line)
command_output += line
if index == 0:
self.ssh.sendline('Y')
elif index == 1:
break
elif index == 2:
logger.debug('End of file')
break
elif index == 3:
timeout_counter += 1
if timeout_counter > timeout:
logger.exception(
'Command timed out, killing process...', exc_info=False
)
return self._send_interrupt(cmd)
except ExceptionPexpect as e:
logger.exception(f'Unexpected exception: {e}')
break
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is introducing several changes in the way that prompts are handled.

  1. Automatic entering of "Y" -- I think this is a bad idea... Usually a confirmation dialog is there because you need to check before doing something dangerous, and having the system automatically choose to proceed seems dangerous.
  2. This does nothing, so it can probably just be removed?
  3. Adding "end of file" may be good, but what was the behavior before?
  4. This seems like a good idea, and I actually like it better than the solution in fix: codeact bug [If running a command that never returns, it gets stuck #1895] #2034, which expands the prompt for something that can probably be done automatically like we do it here.

Comment on lines 46 to +51
_exit_code = self.ssh.before.strip()
return int(_exit_code)
try:
return int(_exit_code)
except ValueError:
logger.error(f'Invalid exit code: {_exit_code}')
return -1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree with @yufansong that we should fix the underlying problem, rather than catching the error here.

@SmartManoj
Copy link
Contributor Author

SmartManoj commented Jun 8, 2024

  1. Automatic entering of "Y" will only affect the sandbox.
  2. We are exiting the loop. ( you mean index==1?)
  3. End-of-file error was not observed before.

logger.exception('Command timed out, killing process...', exc_info=False)
return self._send_interrupt(cmd)
command_output = self.ssh.before
prompts = [
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we inherit from pxssh.pxssh, and override their .prompt method to implement this? It can make the code much more readable?

Copy link
Contributor Author

@SmartManoj SmartManoj Jun 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we move to Paramiko for windows support?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the next week, I'm thinking about completely get rid of SSH, and spin up a websocket client inside sandbox, connect it to the backend, and do things from there -- this will allow us to use ONE event stream for everything which can be cleaner. I can start a draft PR and we can discuss from there i guess.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that would be better for connecting the frontend terminal.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we inherit from pxssh.pxssh, and override their .prompt method to implement this? It can make the code much more readable?

In which file, do you want this to be implemented?

Copy link
Contributor Author

@SmartManoj SmartManoj Jul 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still need to inherit as it is reaching the end of life?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so! We can leave it as is for now probably?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

Copy link
Contributor Author

@SmartManoj SmartManoj Jul 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you reopen it?

@SmartManoj SmartManoj marked this pull request as draft June 16, 2024 06:22
@mamoodi
Copy link
Collaborator

mamoodi commented Jun 30, 2024

@SmartManoj wondering if this is going to be continued or should be closed?

@xingyaoww
Copy link
Collaborator

Let's close it for now since it has been stale for a while! Feel free to reopen if things progress and need review.

@xingyaoww xingyaoww closed this Jul 4, 2024
@SmartManoj
Copy link
Contributor Author

SmartManoj commented Jul 4, 2024

Discussion with @mamoodi on slack,

image

#2404

@SmartManoj SmartManoj mentioned this pull request Jul 11, 2024
@SmartManoj SmartManoj changed the title Processed interactive commands and streamable output in logs Process interactive commands and stream output in logs Jul 20, 2024
@SmartManoj
Copy link
Contributor Author

SmartManoj commented Jul 20, 2024

@neubig

  1. Automatic entering of "Y" will only affect the sandbox.

Confirmation mode will handle this now.

3. End-of-file error was not observed before.

#2427 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants