Improve wait output with recent activity snapshot

This commit is contained in:
Mohamed Boudra
2026-02-22 12:10:38 +07:00
parent afc74d67e2
commit 52336425bc
2 changed files with 67 additions and 19 deletions
+28 -13
View File
@@ -19,6 +19,27 @@ export interface AgentLogsOptions extends CommandOptions {
// Logs command returns void - it outputs directly to console // Logs command returns void - it outputs directly to console
export type AgentLogsResult = void export type AgentLogsResult = void
export const NO_ACTIVITY_MESSAGE = 'No activity to display.'
export async function fetchAgentTimelineItems(
client: DaemonClient,
agentId: string
): Promise<AgentTimelineItem[]> {
return fetchProjectedTimelineItems({ client, agentId })
}
export function formatAgentActivityTranscript(
timelineItems: AgentTimelineItem[],
tailCount?: number
): string {
if (tailCount === 0) {
return ''
}
return curateAgentActivity(
timelineItems,
tailCount !== undefined ? { maxItems: tailCount } : undefined
)
}
function parseTailCount(raw: string | undefined): number | undefined { function parseTailCount(raw: string | undefined): number | undefined {
if (raw === undefined) return undefined if (raw === undefined) return undefined
@@ -100,10 +121,7 @@ export async function runLogsCommand(
} }
// Fetch timeline directly via cursor RPC. // Fetch timeline directly via cursor RPC.
let timelineItems = await fetchProjectedTimelineItems({ let timelineItems = await fetchAgentTimelineItems(client, resolvedId)
client,
agentId: resolvedId,
})
// Apply filter // Apply filter
if (options.filter) { if (options.filter) {
@@ -125,7 +143,7 @@ export async function runLogsCommand(
return return
} }
const transcript = curateAgentActivity(timelineItems, tailCount !== undefined ? { maxItems: tailCount } : undefined) const transcript = formatAgentActivityTranscript(timelineItems, tailCount)
console.log(transcript) console.log(transcript)
} catch (err) { } catch (err) {
const message = err instanceof Error ? err.message : String(err) const message = err instanceof Error ? err.message : String(err)
@@ -147,10 +165,7 @@ async function runFollowMode(
const tailCount = parseTailCount(options.tail) ?? DEFAULT_FOLLOW_TAIL const tailCount = parseTailCount(options.tail) ?? DEFAULT_FOLLOW_TAIL
// First, get existing timeline. // First, get existing timeline.
let existingItems = await fetchProjectedTimelineItems({ let existingItems = await fetchAgentTimelineItems(client, agentId)
client,
agentId,
})
// Apply filter to existing items // Apply filter to existing items
if (options.filter) { if (options.filter) {
@@ -159,8 +174,8 @@ async function runFollowMode(
// Print existing transcript (tail-like behavior) // Print existing transcript (tail-like behavior)
if (tailCount > 0) { if (tailCount > 0) {
const existingTranscript = curateAgentActivity(existingItems, { maxItems: tailCount }) const existingTranscript = formatAgentActivityTranscript(existingItems, tailCount)
if (existingTranscript !== 'No activity to display.') { if (existingTranscript !== NO_ACTIVITY_MESSAGE) {
console.log(existingTranscript) console.log(existingTranscript)
} }
} }
@@ -181,8 +196,8 @@ async function runFollowMode(
return return
} }
// Print each timeline item as it arrives using the curator format // Print each timeline item as it arrives using the curator format
const transcript = curateAgentActivity([item]) const transcript = formatAgentActivityTranscript([item])
if (transcript !== 'No activity to display.') { if (transcript !== NO_ACTIVITY_MESSAGE) {
console.log(transcript) console.log(transcript)
} }
} }
+39 -6
View File
@@ -1,6 +1,7 @@
import type { Command } from 'commander' import type { Command } from 'commander'
import { connectToDaemon, getDaemonHost } from '../../utils/client.js' import { connectToDaemon, getDaemonHost } from '../../utils/client.js'
import type { CommandOptions, SingleResult, OutputSchema, CommandError } from '../../output/index.js' import type { CommandOptions, SingleResult, OutputSchema, CommandError } from '../../output/index.js'
import { fetchAgentTimelineItems, formatAgentActivityTranscript } from './logs.js'
/** Result type for agent wait command */ /** Result type for agent wait command */
export interface AgentWaitResult { export interface AgentWaitResult {
@@ -24,6 +25,28 @@ export interface AgentWaitOptions extends CommandOptions {
host?: string host?: string
} }
const WAIT_ACTIVITY_PREVIEW_COUNT = 5
function appendRecentActivity(message: string, transcript: string | null): string {
if (!transcript || transcript.trim().length === 0) {
return message
}
return `${message}\nLast ${WAIT_ACTIVITY_PREVIEW_COUNT} activity items:\n${transcript}`
}
async function getRecentActivityTranscript(
client: Awaited<ReturnType<typeof connectToDaemon>>,
agentId: string
): Promise<string | null> {
try {
const timelineItems = await fetchAgentTimelineItems(client, agentId)
return formatAgentActivityTranscript(timelineItems, WAIT_ACTIVITY_PREVIEW_COUNT)
} catch {
return null
}
}
/** /**
* Parse duration string to milliseconds. * Parse duration string to milliseconds.
* Supports formats like: 5m, 30s, 1h, 2h30m, 90, etc. * Supports formats like: 5m, 30s, 1h, 2h30m, 90, etc.
@@ -106,6 +129,7 @@ export async function runWaitCommand(
timeoutMs = 10 * 60 * 1000 // default 10 minutes timeoutMs = 10 * 60 * 1000 // default 10 minutes
} }
const timeoutSeconds = Math.floor(timeoutMs / 1000) const timeoutSeconds = Math.floor(timeoutMs / 1000)
const timeoutLabel = `${timeoutSeconds} second${timeoutSeconds === 1 ? '' : 's'}`
let client let client
try { try {
@@ -123,15 +147,24 @@ export async function runWaitCommand(
try { try {
try { try {
const state = await client.waitForFinish(agentIdArg, timeoutMs) const state = await client.waitForFinish(agentIdArg, timeoutMs)
const resolvedAgentId = state.final?.id ?? agentIdArg
const recentActivity =
state.status === 'timeout' || state.status === 'idle'
? await getRecentActivityTranscript(client, resolvedAgentId)
: null
await client.close() await client.close()
if (state.status === 'timeout') { if (state.status === 'timeout') {
return { return {
type: 'single', type: 'single',
data: { data: {
agentId: agentIdArg, agentId: resolvedAgentId,
status: 'timeout', status: 'timeout',
message: `Timed out waiting for agent after ${timeoutSeconds} seconds`, message: appendRecentActivity(
`Agent did not finish within ${timeoutLabel}. Run \`paseo wait ${resolvedAgentId}\` again to keep waiting.`,
recentActivity
),
}, },
schema: agentWaitSchema, schema: agentWaitSchema,
} }
@@ -142,7 +175,7 @@ export async function runWaitCommand(
return { return {
type: 'single', type: 'single',
data: { data: {
agentId: state.final?.id ?? agentIdArg, agentId: resolvedAgentId,
status: 'permission', status: 'permission',
message: permission message: permission
? `Agent is waiting for permission: ${permission.kind}` ? `Agent is waiting for permission: ${permission.kind}`
@@ -156,7 +189,7 @@ export async function runWaitCommand(
return { return {
type: 'single', type: 'single',
data: { data: {
agentId: state.final?.id ?? agentIdArg, agentId: resolvedAgentId,
status: 'error', status: 'error',
message: state.error ?? 'Agent finished with error', message: state.error ?? 'Agent finished with error',
}, },
@@ -168,9 +201,9 @@ export async function runWaitCommand(
return { return {
type: 'single', type: 'single',
data: { data: {
agentId: state.final?.id ?? agentIdArg, agentId: resolvedAgentId,
status: 'idle', status: 'idle',
message: 'Agent is now idle', message: appendRecentActivity('Agent is idle.', recentActivity),
}, },
schema: agentWaitSchema, schema: agentWaitSchema,
} }