mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-21 20:04:55 +00:00
mom: add working indicator and improve stop command
Working Indicator:
- Add '...' to channel messages while mom is processing
- Automatically removed when work completes or stops
- Applies to working message, not status messages
Improved Stop Command:
- Posts separate 'Stopping...' message that updates to 'Stopped'
- Original working message continues updating with tool results
- Clean separation between status and work output
- Properly handles abort during multi-step operations
Clean Stop Reason Handling:
- Agent run() now returns { stopReason } instead of throwing
- Handle 'aborted', 'error', 'stop', 'length', 'toolUse' cases cleanly
- No more exception-based control flow
- Track stopReason from assistant message.stopReason field
New SlackContext Methods:
- replaceMessage() - replace message text instead of appending
- setWorking() - add/remove working indicator
- Improved context tracking for stop command updates
This commit is contained in:
parent
bfe7df6a49
commit
0c6c0f34dd
4 changed files with 104 additions and 23 deletions
|
|
@ -21,12 +21,16 @@ export interface SlackContext {
|
|||
store: ChannelStore;
|
||||
/** Send/update the main message (accumulates text) */
|
||||
respond(text: string): Promise<void>;
|
||||
/** Replace the entire message text (not append) */
|
||||
replaceMessage(text: string): Promise<void>;
|
||||
/** Post a message in the thread under the main message (for verbose details) */
|
||||
respondInThread(text: string): Promise<void>;
|
||||
/** Show/hide typing indicator */
|
||||
setTyping(isTyping: boolean): Promise<void>;
|
||||
/** Upload a file to the channel */
|
||||
uploadFile(filePath: string, title?: string): Promise<void>;
|
||||
/** Set working state (adds/removes working indicator emoji) */
|
||||
setWorking(working: boolean): Promise<void>;
|
||||
}
|
||||
|
||||
export interface MomHandler {
|
||||
|
|
@ -201,6 +205,8 @@ export class MomBot {
|
|||
let messageTs: string | null = null;
|
||||
let accumulatedText = "";
|
||||
let isThinking = true; // Track if we're still in "thinking" state
|
||||
let isWorking = true; // Track if still processing
|
||||
const workingIndicator = " ...";
|
||||
let updatePromise: Promise<void> = Promise.resolve();
|
||||
|
||||
return {
|
||||
|
|
@ -227,18 +233,21 @@ export class MomBot {
|
|||
accumulatedText += "\n" + responseText;
|
||||
}
|
||||
|
||||
// Add working indicator if still working
|
||||
const displayText = isWorking ? accumulatedText + workingIndicator : accumulatedText;
|
||||
|
||||
if (messageTs) {
|
||||
// Update existing message
|
||||
await this.webClient.chat.update({
|
||||
channel: event.channel,
|
||||
ts: messageTs,
|
||||
text: accumulatedText,
|
||||
text: displayText,
|
||||
});
|
||||
} else {
|
||||
// Post initial message
|
||||
const result = await this.webClient.chat.postMessage({
|
||||
channel: event.channel,
|
||||
text: accumulatedText,
|
||||
text: displayText,
|
||||
});
|
||||
messageTs = result.ts as string;
|
||||
}
|
||||
|
|
@ -267,8 +276,8 @@ export class MomBot {
|
|||
},
|
||||
setTyping: async (isTyping: boolean) => {
|
||||
if (isTyping && !messageTs) {
|
||||
// Post initial "thinking" message
|
||||
accumulatedText = "_Thinking..._";
|
||||
// Post initial "thinking" message (... auto-appended by working indicator)
|
||||
accumulatedText = "_Thinking_";
|
||||
const result = await this.webClient.chat.postMessage({
|
||||
channel: event.channel,
|
||||
text: accumulatedText,
|
||||
|
|
@ -288,6 +297,46 @@ export class MomBot {
|
|||
title: fileName,
|
||||
});
|
||||
},
|
||||
replaceMessage: async (text: string) => {
|
||||
updatePromise = updatePromise.then(async () => {
|
||||
// Replace the accumulated text entirely
|
||||
accumulatedText = text;
|
||||
|
||||
const displayText = isWorking ? accumulatedText + workingIndicator : accumulatedText;
|
||||
|
||||
if (messageTs) {
|
||||
await this.webClient.chat.update({
|
||||
channel: event.channel,
|
||||
ts: messageTs,
|
||||
text: displayText,
|
||||
});
|
||||
} else {
|
||||
// Post initial message
|
||||
const result = await this.webClient.chat.postMessage({
|
||||
channel: event.channel,
|
||||
text: displayText,
|
||||
});
|
||||
messageTs = result.ts as string;
|
||||
}
|
||||
});
|
||||
await updatePromise;
|
||||
},
|
||||
setWorking: async (working: boolean) => {
|
||||
updatePromise = updatePromise.then(async () => {
|
||||
isWorking = working;
|
||||
|
||||
// If we have a message, update it to add/remove indicator
|
||||
if (messageTs) {
|
||||
const displayText = isWorking ? accumulatedText + workingIndicator : accumulatedText;
|
||||
await this.webClient.chat.update({
|
||||
channel: event.channel,
|
||||
ts: messageTs,
|
||||
text: displayText,
|
||||
});
|
||||
}
|
||||
});
|
||||
await updatePromise;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue