Skip to content

Commit cdbc045

Browse files
authored
Merge pull request aws#6864 from tsmithsz/feature/agentic-chat
feat(chat): Stream executeBash output to chat
2 parents 63d5ab5 + 811869b commit cdbc045

File tree

5 files changed

+78
-2
lines changed

5 files changed

+78
-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, toolUse.toolUseId)
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, toolUseId: string | undefined) {
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: toolUseId ?? `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: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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 toolUseId: string | undefined,
22+
private readonly logger = getLogger('chatStream')
23+
) {
24+
super()
25+
this.logger.debug(`ChatStream created for tabID: ${tabID}, triggerID: ${triggerID}`)
26+
}
27+
28+
override _write(chunk: Buffer, encoding: BufferEncoding, callback: (error?: Error | null) => void): void {
29+
const text = chunk.toString()
30+
this.accumulatedLogs += text
31+
this.logger.debug(`ChatStream received chunk: ${text}`)
32+
this.messenger.sendPartialBashToolLog(
33+
`\`\`\`bash\n${this.accumulatedLogs}\`\`\``,
34+
this.tabID,
35+
this.triggerID,
36+
this.toolUseId
37+
)
38+
callback()
39+
}
40+
41+
override _final(callback: (error?: Error | null) => void): void {
42+
if (this.accumulatedLogs.trim().length > 0) {
43+
this.messenger.sendPartialBashToolLog(
44+
`\`\`\`bash\n${this.accumulatedLogs}\`\`\``,
45+
this.tabID,
46+
this.triggerID,
47+
this.toolUseId
48+
)
49+
}
50+
callback()
51+
}
52+
}

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)