Skip to content

Commit 876e8c3

Browse files
committed
feat(chat): Stream executeBash output to chat
1 parent 8a75883 commit 876e8c3

File tree

5 files changed

+71
-2
lines changed

5 files changed

+71
-2
lines changed

packages/core/src/codewhispererChat/controllers/chat/controller.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ import { FsRead, FsReadParams } from '../../tools/fsRead'
8888
import { InvokeOutput, OutputKind } from '../../tools/toolShared'
8989
import { FsWrite, FsWriteCommand } from '../../tools/fsWrite'
9090
import { ExecuteBash, ExecuteBashParams } from '../../tools/executeBash'
91+
import { ChatStream } from '../../tools/chatStream'
9192

9293
export interface ChatControllerMessagePublishers {
9394
readonly processPromptChatMessage: MessagePublisher<PromptMessage>
@@ -951,7 +952,8 @@ export class ChatController {
951952
case 'executeBash': {
952953
const executeBash = new ExecuteBash(toolUse.input as unknown as ExecuteBashParams)
953954
await executeBash.validate()
954-
result = await executeBash.invoke(process.stdout)
955+
const chatStream = new ChatStream(this.messenger, tabID, triggerID)
956+
result = await executeBash.invoke(chatStream)
955957
break
956958
}
957959
case 'fsRead': {

packages/core/src/codewhispererChat/controllers/chat/messenger/messenger.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,27 @@ export class Messenger {
438438
)
439439
}
440440

441+
public sendPartialBashToolLog(message: string, tabID: string, triggerID: string) {
442+
this.dispatcher.sendChatMessage(
443+
new ChatMessage(
444+
{
445+
message,
446+
messageType: 'answer-part',
447+
followUps: undefined,
448+
followUpsHeader: undefined,
449+
relatedSuggestions: undefined,
450+
triggerID,
451+
messageID: `tool-output`,
452+
userIntent: undefined,
453+
codeBlockLanguage: 'plaintext',
454+
contextList: undefined,
455+
canBeVoted: false,
456+
},
457+
tabID
458+
)
459+
)
460+
}
461+
441462
private editorContextMenuCommandVerbs: Map<EditorContextCommandType, string> = new Map([
442463
['aws.amazonq.explainCode', 'Explain'],
443464
['aws.amazonq.explainIssue', 'Explain'],
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { Writable } from 'stream'
7+
import { getLogger } from '../../shared/logger/logger'
8+
import { Messenger } from '../controllers/chat/messenger/messenger'
9+
10+
/**
11+
* A writable stream that feeds each chunk/line to the chat UI.
12+
* Used for streaming tool output (like bash execution) to the chat interface.
13+
*/
14+
export class ChatStream extends Writable {
15+
private accumulatedLogs = ''
16+
17+
public constructor(
18+
private readonly messenger: Messenger,
19+
private readonly tabID: string,
20+
private readonly triggerID: string,
21+
private readonly logger = getLogger('chatStream')
22+
) {
23+
super()
24+
this.logger.debug(`ChatStream created for tabID: ${tabID}, triggerID: ${triggerID}`)
25+
}
26+
27+
override _write(chunk: Buffer, encoding: BufferEncoding, callback: (error?: Error | null) => void): void {
28+
const text = chunk.toString()
29+
this.accumulatedLogs += text
30+
this.logger.debug(`ChatStream received chunk: ${text}`)
31+
this.messenger.sendPartialBashToolLog(`\`\`\`bash\n${this.accumulatedLogs}\`\`\``, this.tabID, this.triggerID)
32+
callback()
33+
}
34+
35+
override _final(callback: (error?: Error | null) => void): void {
36+
if (this.accumulatedLogs.trim().length > 0) {
37+
this.messenger.sendPartialBashToolLog(
38+
`\`\`\`bash\n${this.accumulatedLogs}\`\`\``,
39+
this.tabID,
40+
this.triggerID
41+
)
42+
}
43+
callback()
44+
}
45+
}

packages/core/src/codewhispererChat/tools/executeBash.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,9 @@ export class ExecuteBash {
126126

127127
private static handleChunk(chunk: string, buffer: string[], updates: Writable) {
128128
try {
129+
updates.write(chunk)
129130
const lines = chunk.split(/\r?\n/)
130131
for (const line of lines) {
131-
updates.write(`${line}\n`)
132132
buffer.push(line)
133133
if (buffer.length > lineCount) {
134134
buffer.shift()

packages/core/src/shared/logger/logger.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export type LogTopic =
1919
| 'fsRead'
2020
| 'fsWrite'
2121
| 'executeBash'
22+
| 'chatStream'
2223
| 'unknown'
2324

2425
class ErrorLog {

0 commit comments

Comments
 (0)