Improve wait output with recent activity snapshot
This commit is contained in:
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user