Skip to content

Conversation

@yueny2020
Copy link
Contributor

Problem

  • fix shell command execution output markdown block issue
  • When the child process of bash command execution writes to both stdout and stderr, we need to main the output is processed in the exact order it was generated by the child process.

Solution

  • Before this change
    image

  • After this change
    image


  • Treat all work as PUBLIC. Private feature/x branches will not be squash-merged at release time.
  • Your code changes must meet the guidelines in CONTRIBUTING.md.
  • License: I confirm that my contribution is made under the terms of the Apache 2.0 license.

@yueny2020 yueny2020 requested a review from a team as a code owner April 10, 2025 03:57
@github-actions
Copy link

  • This pull request modifies code in src/* but no tests were added/updated.
    • Confirm whether tests should be added or ensure the PR description explains why tests are not required.
  • This pull request implements a feat or fix, so it must include a changelog entry (unless the fix is for an unreleased feature). Review the changelog guidelines.
    • Note: beta or "experiment" features that have active users should announce fixes in the changelog.
    • If this is not a feature or fix, use an appropriate type from the title guidelines. For example, telemetry-only changes should use the telemetry type.

}
}

class AtomicBoolean {
Copy link
Contributor

Choose a reason for hiding this comment

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

? javascript is single-thread, what is the purpose of this?

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, javascript is single-thread, but we have the use case that one process can send bash command execution output to stdout and stderr, which the streaming of stdout and stderr is async.

Copy link
Contributor

Choose a reason for hiding this comment

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

javascript has a lot of asynchrony, but each async execution context is executed fully until a async call, and is not "preemptible". getAndSet() is not doing anything useful here.

Copy link
Contributor

Choose a reason for hiding this comment

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

// This ensures that the output is processed in the exact order it was generated by the child process.
const outputQueue: TimestampedChunk[] = []
let processingQueue = false
const firstChunk = new AtomicBoolean(true)
Copy link
Contributor

Choose a reason for hiding this comment

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

oh, I see that you are using this as a shared lock. That's different than an atomic boolean.

If you want a shared lock, use AsyncLock:

private static _asyncLock = new AsyncLock()

But this risks deadlock. It would be less risky to collect stdout and stderr separately, then combine them later, if that's important to you.

Copy link
Contributor Author

@yueny2020 yueny2020 Apr 10, 2025

Choose a reason for hiding this comment

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

I think as the javascript event loop is a single thread, we can use a simple boolean variable(isFirstChunk) in closure to replace the AsyncLock in my use case.

  1. The onStdout and onStderr callbacks are never truly executing simultaneously for one bash command execution - they're queued and executed one after another on the event loop.

  2. The only shared state is the simple boolean flag (isFirstChunk) that's only set once from true to false. and there is no any other async operations.

Overall, the usage of AsyncLock adds unnecessary overhead for such a simple operation.

I can remove the atomic inner class(as it causes confusion). just use var and a function.

            // Use a closure boolean value firstChunk and a function to get and set its value
            let isFirstChunk = true
            const getAndSetFirstChunk = (newValue: boolean): boolean => {
                const oldValue = isFirstChunk
                isFirstChunk = newValue
                return oldValue
            }

Copy link
Contributor

Choose a reason for hiding this comment

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

set its value atomically

what is the purpose of mentioning this? there is no atomicity provided by this function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, remove it from the comment.

let firstStderrChunk = true
// Use a closure boolean value firstChunk and a function to get and set its value atomically
let isFirstChunk = true
const getAndSetFirstChunk = (newValue: boolean): boolean => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

the function getAndSetFirstChunk can avoid duplicate code in line 260 and line 271.


let firstChunk = true
let firstStderrChunk = true
// Use a closure boolean value firstChunk and a function to get and set its value atomically
Copy link
Contributor

Choose a reason for hiding this comment

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

This entire comment is likely to cause confusion. The only really purpose of this function in this codebase is to save a few lines of code. That's fine, but that is different than what this comment says.

timestamp: number
isStdout: boolean
content: string
isFirst: boolean
Copy link
Contributor

Choose a reason for hiding this comment

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

this would be a field that actually needs a brief comment that gives insight into its purpose.

@yueny2020 yueny2020 force-pushed the feature/agentic-chat branch from 541c479 to 72a589b Compare April 10, 2025 18:48
Copy link
Contributor

@justinmk3 justinmk3 left a comment

Choose a reason for hiding this comment

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

LGTM after comments are fixed

@zixlin7 zixlin7 merged commit c3d087a into aws:feature/agentic-chat Apr 10, 2025
21 of 22 checks passed
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.

4 participants