feat: show tool activity sub-lines in progress messages
Display subagent tool descriptions as sub-lines under the main progress text, updating in-place via Discord message edit. Shows up to 5 recent tool activities (e.g., "Reading index.ts").
This commit is contained in:
@@ -32,7 +32,7 @@ interface ContainerInput {
|
|||||||
|
|
||||||
interface ContainerOutput {
|
interface ContainerOutput {
|
||||||
status: 'success' | 'error';
|
status: 'success' | 'error';
|
||||||
phase?: 'progress' | 'final';
|
phase?: 'progress' | 'final' | 'tool-activity';
|
||||||
result: string | null;
|
result: string | null;
|
||||||
newSessionId?: string;
|
newSessionId?: string;
|
||||||
error?: string;
|
error?: string;
|
||||||
@@ -554,6 +554,7 @@ async function runQuery(
|
|||||||
if (message.type === 'system' && (message as { subtype?: string }).subtype === 'task_progress') {
|
if (message.type === 'system' && (message as { subtype?: string }).subtype === 'task_progress') {
|
||||||
const tp = message as Record<string, unknown>;
|
const tp = message as Record<string, unknown>;
|
||||||
const summary = typeof tp.summary === 'string' ? tp.summary : '';
|
const summary = typeof tp.summary === 'string' ? tp.summary : '';
|
||||||
|
const description = typeof tp.description === 'string' ? tp.description : '';
|
||||||
if (summary) {
|
if (summary) {
|
||||||
log(`Subagent progress: ${summary.slice(0, 200)}`);
|
log(`Subagent progress: ${summary.slice(0, 200)}`);
|
||||||
writeOutput({
|
writeOutput({
|
||||||
@@ -563,6 +564,14 @@ async function runQuery(
|
|||||||
newSessionId,
|
newSessionId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (description) {
|
||||||
|
writeOutput({
|
||||||
|
status: 'success',
|
||||||
|
phase: 'tool-activity',
|
||||||
|
result: description,
|
||||||
|
newSessionId,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.type === 'system' && (message as { subtype?: string }).subtype === 'task_started') {
|
if (message.type === 'system' && (message as { subtype?: string }).subtype === 'task_started') {
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export interface AgentInput {
|
|||||||
export interface AgentOutput {
|
export interface AgentOutput {
|
||||||
status: 'success' | 'error';
|
status: 'success' | 'error';
|
||||||
result: string | null;
|
result: string | null;
|
||||||
phase?: 'progress' | 'final';
|
phase?: 'progress' | 'final' | 'tool-activity';
|
||||||
newSessionId?: string;
|
newSessionId?: string;
|
||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
@@ -238,7 +238,11 @@ export async function runAgentProcess(
|
|||||||
const lines = chunk.trim().split('\n');
|
const lines = chunk.trim().split('\n');
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
if (!line) continue;
|
if (!line) continue;
|
||||||
if (line.includes('Turn in progress') || line.includes('Subagent') || line.includes('Intermediate assistant')) {
|
if (
|
||||||
|
line.includes('Turn in progress') ||
|
||||||
|
line.includes('Subagent') ||
|
||||||
|
line.includes('Intermediate assistant')
|
||||||
|
) {
|
||||||
logger.info(
|
logger.info(
|
||||||
{ group: group.name, chatJid: input.chatJid, runId: input.runId },
|
{ group: group.name, chatJid: input.chatJid, runId: input.runId },
|
||||||
line.replace(/^\[.*?\]\s*/, ''),
|
line.replace(/^\[.*?\]\s*/, ''),
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export class MessageTurnController {
|
|||||||
private latestProgressText: string | null = null;
|
private latestProgressText: string | null = null;
|
||||||
private previousProgressText: string | null = null;
|
private previousProgressText: string | null = null;
|
||||||
private pendingProgressText: string | null = null;
|
private pendingProgressText: string | null = null;
|
||||||
|
private toolActivities: string[] = [];
|
||||||
private latestProgressRendered: string | null = null;
|
private latestProgressRendered: string | null = null;
|
||||||
private progressMessageId: string | null = null;
|
private progressMessageId: string | null = null;
|
||||||
private progressStartedAt: number | null = null;
|
private progressStartedAt: number | null = null;
|
||||||
@@ -103,6 +104,16 @@ export class MessageTurnController {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result.phase === 'tool-activity') {
|
||||||
|
if (text) {
|
||||||
|
this.addToolActivity(text);
|
||||||
|
}
|
||||||
|
if (!this.poisonedSessionDetected) {
|
||||||
|
this.resetIdleTimer();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (result.phase === 'progress') {
|
if (result.phase === 'progress') {
|
||||||
if (text) {
|
if (text) {
|
||||||
this.bufferProgress(text);
|
this.bufferProgress(text);
|
||||||
@@ -217,11 +228,14 @@ export class MessageTurnController {
|
|||||||
if (minutes > 0) elapsedParts.push(`${minutes}분`);
|
if (minutes > 0) elapsedParts.push(`${minutes}분`);
|
||||||
elapsedParts.push(`${seconds}초`);
|
elapsedParts.push(`${seconds}초`);
|
||||||
|
|
||||||
|
const activityLines = this.toolActivities.length > 0
|
||||||
|
? '\n' + this.toolActivities.map((a) => `├ ${a}`).join('\n')
|
||||||
|
: '';
|
||||||
const suffix = `\n\n${elapsedParts.join(' ')}`;
|
const suffix = `\n\n${elapsedParts.join(' ')}`;
|
||||||
const maxText = 2000 - TASK_STATUS_MESSAGE_PREFIX.length - suffix.length;
|
const maxText = 2000 - TASK_STATUS_MESSAGE_PREFIX.length - activityLines.length - suffix.length;
|
||||||
const truncated =
|
const truncated =
|
||||||
text.length > maxText ? text.slice(0, maxText - 1) + '…' : text;
|
text.length > maxText ? text.slice(0, maxText - 1) + '…' : text;
|
||||||
return `${TASK_STATUS_MESSAGE_PREFIX}${truncated}${suffix}`;
|
return `${TASK_STATUS_MESSAGE_PREFIX}${truncated}${activityLines}${suffix}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private clearProgressTicker(): void {
|
private clearProgressTicker(): void {
|
||||||
@@ -233,6 +247,7 @@ export class MessageTurnController {
|
|||||||
private resetProgressState(): void {
|
private resetProgressState(): void {
|
||||||
this.clearProgressTicker();
|
this.clearProgressTicker();
|
||||||
this.pendingProgressText = null;
|
this.pendingProgressText = null;
|
||||||
|
this.toolActivities = [];
|
||||||
this.latestProgressText = null;
|
this.latestProgressText = null;
|
||||||
this.previousProgressText = null;
|
this.previousProgressText = null;
|
||||||
this.latestProgressRendered = null;
|
this.latestProgressRendered = null;
|
||||||
@@ -252,6 +267,22 @@ export class MessageTurnController {
|
|||||||
void this.sendProgressMessage(this.pendingProgressText);
|
void this.sendProgressMessage(this.pendingProgressText);
|
||||||
}
|
}
|
||||||
this.pendingProgressText = text;
|
this.pendingProgressText = text;
|
||||||
|
this.toolActivities = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a tool activity line and update the progress message in-place.
|
||||||
|
*/
|
||||||
|
private addToolActivity(description: string): void {
|
||||||
|
const MAX_ACTIVITIES = 5;
|
||||||
|
this.toolActivities.push(description);
|
||||||
|
if (this.toolActivities.length > MAX_ACTIVITIES) {
|
||||||
|
this.toolActivities = this.toolActivities.slice(-MAX_ACTIVITIES);
|
||||||
|
}
|
||||||
|
// Update the displayed progress message with tool activity sub-lines
|
||||||
|
if (this.latestProgressText && this.progressMessageId) {
|
||||||
|
void this.syncTrackedProgressMessage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user