这是indexloc提供的服务,不要输入任何密码
Skip to content

feat(tools): add support for streaming command output in bash_tool.go #177

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

Vinay-Khanagavi
Copy link
Contributor

@Vinay-Khanagavi Vinay-Khanagavi commented May 8, 2025

Adds support for streaming command output in bash_tool.go for commands like kubectl logs -f and tail -f.

  • Detects streaming commands by checking for -f or --follow flags.
  • Streams stdout/stderr in real time to the user.

Prints a message:
Streaming output... Press CTRL-C to stop streaming and return to the prompt.

  • Handles CTRL-C gracefully, returning to the REPL without exiting the tool.
  • Non-streaming commands retain their previous behavior.

This improves the UX for monitoring long-running or initializing workloads.

Closes #122

Copy link
Member

@droot droot left a comment

Choose a reason for hiding this comment

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

Thanks @Vinay-Khanagavi for taking a crack at it,

I have some comments.

// Detect streaming commands (e.g., kubectl logs -f, tail -f)
isStreaming := false
for _, arg := range cmd.Args {
if arg == "-f" || arg == "--follow" {
Copy link
Member

Choose a reason for hiding this comment

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

I suspect it will treat kubectl apply -f a streaming command. Probably better to be very specific here and we can check for presense of ("kubectl logs" and "-f") or ("kubectl tail" and "-f") ...and so on...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For streaming detection, do you prefer I check specifically for commands like ( "kubectl logs -f") or ("kubectl tail -f") (i.e., both the base command and the -f flag), instead of just any command with -f?
Let me know if you have a preferred way to match these patterns in the codebase.

@@ -122,12 +125,86 @@ type ExecResult struct {
}

func executeCommand(cmd *exec.Cmd) (*ExecResult, error) {
// Detect streaming commands (e.g., kubectl logs -f, tail -f)
Copy link
Member

Choose a reason for hiding this comment

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

it will be good to add the original github issue that prompted this change.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yup! I’ll add a reference to the original GitHub issue (e.g., Closes #122) in the code comments,
Let me know if you have a preferred location for this reference (code comment vs. PR body).


if isStreaming {
// Print streaming message
fmt.Fprintln(os.Stdout, "\nStreaming output... Press CTRL-C to stop streaming and return to the prompt.")
Copy link
Member

Choose a reason for hiding this comment

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

Avoid writing to the os.Stdout directly. Use the ui instance to write to the screen. You will have to make ui instance available from the caller to all the way here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for pointing out the need to use the ui instance instead of writing directly to os.Stdout.

Do you have any suggestions or examples from the codebase on the best way to pass the ui instance down to executeCommand (and the goroutines), especially since it’s currently not available at this level?

Would you recommend passing it as a parameter, using context, or is there a preferred pattern in this project?

@droot
Copy link
Member

droot commented May 13, 2025

@Vinay-Khanagavi really swamped right now, I will get to this PR tomorrow, sorry for the delay.

Comment on lines 139 to 162
if isStreaming {
// Print streaming message
fmt.Fprintln(os.Stdout, "\nStreaming output... Press CTRL-C to stop streaming and return to the prompt.")

stdoutPipe, err := cmd.StdoutPipe()
if err != nil {
results.Error = err.Error()
return results, err
}
stderrPipe, err := cmd.StderrPipe()
if err != nil {
results.Error = err.Error()
return results, err
}

if err := cmd.Start(); err != nil {
results.Error = err.Error()
return results, err
}

// Channel to catch interrupt
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
defer signal.Stop(interrupt)
Copy link
Contributor

Choose a reason for hiding this comment

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

This Signal will also interrupt the current conversation

  Running: kubectl logs echo-pod -f

Streaming output... Press CTRL-C to stop streaming and return to the prompt.
zvdy was here
zvdy was here
zvdy was here
zvdy was here
zvdy was here
zvdy was here
zvdy was here
zvdy was here
zvdy was here
zvdy was here
zvdy was here
zvdy was here
zvdy was here
zvdy was here
zvdy was here
zvdy was here
zvdy was here
zvdy was here
zvdy was here
^CReceived signal, shutting down... interrupt

Copy link
Contributor Author

@Vinay-Khanagavi Vinay-Khanagavi May 16, 2025

Choose a reason for hiding this comment

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

Thanks for raising this! @zvdy
I've updated the code to proactively block not just kubectl get ... -w but also other blocking/streaming commands like kubectl logs ... -f. Now, if the model tries to run a command with -w or -f in unattended mode, it will return a clear error message instead of running the command and blocking the session.

So, you won’t see the infinite streaming or need to manually interrupt anymore.
If you spot any other kubectl commands that can block like this, let me know and I’ll add them to the block list as well!

Let me know if you have any other suggestions or if you want to test further. Thanks for reviewing!

@Vinay-Khanagavi
Copy link
Contributor Author

Thank you for the review.
@droot — I've documented the tests I ran with kubectl-ai in the following doc:
Testing Report

Please feel free to review and suggest any additional changes if needed. Thank you!

@zvdy
Copy link
Contributor

zvdy commented May 16, 2025

Another more complex edge case would be exec -it bash , maybe this is out of scope for kubectl-ai checking status and executing commands on the pods directly to fix/manage stuff.

Also, my idea was to allow the cli to stream the messages "infinitely" until user wants to stop and feed it back to the ai so it can work upon the data, analyse and take action.

Take as an example a microservice that logs out that the service might experience high response times due to CPU/MEMORY/IO resource, the probes might be passing but due to bad scaling and overall configuration there is a bottleneck that can be fixed. This are more complex issues, and I'm assuming the verbosity of the pod in question, but having the model read that, will guide them into modifying the definition accordingly with the demand of the service.

What do you think? @Vinay-Khanagavi @droot

@Vinay-Khanagavi
Copy link
Contributor Author

Vinay-Khanagavi commented May 16, 2025

This could be a game-changer for Kubernetes troubleshooting and self-healing, but will require careful design for safety, cost, and user trust. Would love to hear your perspectives on scope, priorities, and potential pilot features!

@zvdy @droot — would appreciate your thoughts!

I've been thinking about this as well. My main concerns center on security, cost, and ensuring that users retain full control over any automated actions. I think this is a great direction for future exploration, maybe as an opt-in “advanced mode” or with clear user controls, nice thanks for mentioning.

  • On the technical side, we’re already blocking commands that can cause the tool to hang in unattended mode (like kubectl get ... -w and kubectl logs ... -f. ). Another important edge case is interactive commands such as kubectl exec -it ... bash, which expect a TTY and could also block or create security risks. For now, kubectl-ai is focused on non-interactive automation (status checks, applying manifests, etc.), so handling fully interactive sessions is out of scope. However, we can proactively detect and block these commands, returning a clear error message to the user if the model tries to run them.

@droot
Copy link
Member

droot commented May 20, 2025

Sorry @Vinay-Khanagavi , This PR has turned out to be more complex than I thought. Thanks @zvdy for finding the edge cases and input.

This PR is challenging us into another area of agentic design (collab with a human and how to share control of interaction with the environment as well as I/O) -- when agent requires user's attention (blocking command), it needs to pass the control to the end-user for that action. (think browser based agent, that requires asking user to login etc.)

I would like us to do the following:

  1. Audit all kubectl commands to discover the edge cases
  2. Agree on the agent's behavior (from the perspective of the end-user's goal, sometime running a blocking command is not expected by the end-user and sometime blocking command is an exception and control needs to be passed to the end-user). Here going through 3-4 concrete CUJs (user journeys) helps.
  3. And then proceed with the final implementation.

Looking at the PR, I think we will have good handle on the technical aspect, but more work is needed on the audit and behavior definition.

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.

FR: please support streaming of logs
3 participants