mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-17 05:00:16 +00:00
feat(mom): reduce tool verbosity in main Slack messages
- During execution: show tool labels, thinking, and text in main message - After completion: replace main message with only final assistant text - Post thinking (italic) and text to thread for full audit trail - Add promise queue to ensure ctx.respond calls execute sequentially - Add log.logThinking() and log.logResponse() for console output - Get final text from agent.state.messages instead of tracking Closes #65
This commit is contained in:
parent
318254bff4
commit
effb4d0b7c
2 changed files with 75 additions and 14 deletions
|
|
@ -377,6 +377,22 @@ export function createAgentRunner(sandboxConfig: SandboxConfig): AgentRunner {
|
||||||
// Track stop reason
|
// Track stop reason
|
||||||
let stopReason = "stop";
|
let stopReason = "stop";
|
||||||
|
|
||||||
|
// Promise queue to ensure ctx.respond/respondInThread calls execute in order
|
||||||
|
const queue = {
|
||||||
|
chain: Promise.resolve(),
|
||||||
|
enqueue<T>(fn: () => Promise<T>): Promise<T> {
|
||||||
|
const result = this.chain.then(fn);
|
||||||
|
this.chain = result.then(
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
|
); // swallow errors for chain
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
flush(): Promise<void> {
|
||||||
|
return this.chain;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// Subscribe to events
|
// Subscribe to events
|
||||||
agent.subscribe(async (event: AgentEvent) => {
|
agent.subscribe(async (event: AgentEvent) => {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
|
|
@ -405,7 +421,7 @@ export function createAgentRunner(sandboxConfig: SandboxConfig): AgentRunner {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Show label in main message only
|
// Show label in main message only
|
||||||
await ctx.respond(`_${label}_`);
|
queue.enqueue(() => ctx.respond(`_${label}_`));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -453,11 +469,11 @@ export function createAgentRunner(sandboxConfig: SandboxConfig): AgentRunner {
|
||||||
|
|
||||||
threadMessage += "*Result:*\n```\n" + threadResult + "\n```";
|
threadMessage += "*Result:*\n```\n" + threadResult + "\n```";
|
||||||
|
|
||||||
await ctx.respondInThread(threadMessage);
|
queue.enqueue(() => ctx.respondInThread(threadMessage));
|
||||||
|
|
||||||
// Show brief error in main message if failed
|
// Show brief error in main message if failed
|
||||||
if (event.isError) {
|
if (event.isError) {
|
||||||
await ctx.respond(`_Error: ${truncate(resultStr, 200)}_`);
|
queue.enqueue(() => ctx.respond(`_Error: ${truncate(resultStr, 200)}_`));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -495,17 +511,32 @@ export function createAgentRunner(sandboxConfig: SandboxConfig): AgentRunner {
|
||||||
totalUsage.cost.total += assistantMsg.usage.cost.total;
|
totalUsage.cost.total += assistantMsg.usage.cost.total;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract text from assistant message
|
// Extract thinking and text from assistant message
|
||||||
const content = event.message.content;
|
const content = event.message.content;
|
||||||
let text = "";
|
const thinkingParts: string[] = [];
|
||||||
|
const textParts: string[] = [];
|
||||||
for (const part of content) {
|
for (const part of content) {
|
||||||
if (part.type === "text") {
|
if (part.type === "thinking") {
|
||||||
text += part.text;
|
thinkingParts.push(part.thinking);
|
||||||
|
} else if (part.type === "text") {
|
||||||
|
textParts.push(part.text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const text = textParts.join("\n");
|
||||||
|
|
||||||
|
// Post thinking to main message and thread
|
||||||
|
for (const thinking of thinkingParts) {
|
||||||
|
log.logThinking(logCtx, thinking);
|
||||||
|
queue.enqueue(() => ctx.respond(`_${thinking}_`));
|
||||||
|
queue.enqueue(() => ctx.respondInThread(`_${thinking}_`));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post text to main message and thread
|
||||||
if (text.trim()) {
|
if (text.trim()) {
|
||||||
await ctx.respond(text);
|
log.logResponse(logCtx, text);
|
||||||
log.logResponseComplete(logCtx, text.length);
|
queue.enqueue(() => ctx.respond(text));
|
||||||
|
queue.enqueue(() => ctx.respondInThread(text));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -523,10 +554,26 @@ export function createAgentRunner(sandboxConfig: SandboxConfig): AgentRunner {
|
||||||
|
|
||||||
await agent.prompt(userPrompt);
|
await agent.prompt(userPrompt);
|
||||||
|
|
||||||
|
// Wait for all queued respond calls to complete
|
||||||
|
await queue.flush();
|
||||||
|
|
||||||
|
// Get final assistant message text from agent state and replace main message
|
||||||
|
const messages = agent.state.messages;
|
||||||
|
const lastAssistant = messages.filter((m) => m.role === "assistant").pop();
|
||||||
|
const finalText =
|
||||||
|
lastAssistant?.content
|
||||||
|
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
||||||
|
.map((c) => c.text)
|
||||||
|
.join("\n") || "";
|
||||||
|
if (finalText.trim()) {
|
||||||
|
await ctx.replaceMessage(finalText);
|
||||||
|
}
|
||||||
|
|
||||||
// Log usage summary if there was any usage
|
// Log usage summary if there was any usage
|
||||||
if (totalUsage.cost.total > 0) {
|
if (totalUsage.cost.total > 0) {
|
||||||
const summary = log.logUsageSummary(logCtx, totalUsage);
|
const summary = log.logUsageSummary(logCtx, totalUsage);
|
||||||
await ctx.respondInThread(summary);
|
queue.enqueue(() => ctx.respondInThread(summary));
|
||||||
|
await queue.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
return { stopReason };
|
return { stopReason };
|
||||||
|
|
|
||||||
|
|
@ -118,10 +118,24 @@ export function logResponseStart(ctx: LogContext): void {
|
||||||
console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} → Streaming response...`));
|
console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} → Streaming response...`));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function logResponseComplete(ctx: LogContext, charCount: number): void {
|
export function logThinking(ctx: LogContext, thinking: string): void {
|
||||||
console.log(
|
console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} 💭 Thinking`));
|
||||||
chalk.yellow(`${timestamp()} ${formatContext(ctx)} ✓ Response sent (${charCount.toLocaleString()} chars)`),
|
const truncated = truncate(thinking, 1000);
|
||||||
);
|
const indented = truncated
|
||||||
|
.split("\n")
|
||||||
|
.map((line) => ` ${line}`)
|
||||||
|
.join("\n");
|
||||||
|
console.log(chalk.dim(indented));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function logResponse(ctx: LogContext, text: string): void {
|
||||||
|
console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} 💬 Response`));
|
||||||
|
const truncated = truncate(text, 1000);
|
||||||
|
const indented = truncated
|
||||||
|
.split("\n")
|
||||||
|
.map((line) => ` ${line}`)
|
||||||
|
.join("\n");
|
||||||
|
console.log(chalk.dim(indented));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attachments
|
// Attachments
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue