diff --git a/dashboard/src/components/activity/ActivityTimeline.tsx b/dashboard/src/components/activity/ActivityTimeline.tsx index ec530371..8b3e5932 100644 --- a/dashboard/src/components/activity/ActivityTimeline.tsx +++ b/dashboard/src/components/activity/ActivityTimeline.tsx @@ -1737,12 +1737,12 @@ function summarizeStatusUpdatesForCard(item: LiveActivityItem): string | null { if (isBuffered) { if (updates.length > 0) { const first = updates[0]; - return `Queued ${updates.length} update${updates.length === 1 ? '' : 's'}: ${first.label}${first.status ? ` → ${first.status}` : ''}`; + return `Updates being applied: ${updates.length} queued update${updates.length === 1 ? '' : 's'} · ${first.label}${first.status ? ` → ${first.status}` : ''}`; } if (statusUpdatesApplied !== null && statusUpdatesApplied > 0) { - return `Queued ${statusUpdatesApplied} status update${statusUpdatesApplied === 1 ? '' : 's'} for sync`; + return `Updates being applied: ${statusUpdatesApplied} status update${statusUpdatesApplied === 1 ? '' : 's'} queued for sync`; } - return 'Queued status updates for sync'; + return 'Updates being applied: status updates queued for sync'; } if (statusUpdatesApplied !== null && statusUpdatesApplied > 0) { @@ -6473,20 +6473,25 @@ export const ActivityTimeline = memo(function ActivityTimeline({ const commitSha = metadataString(outcomes, ['commit_sha', 'commitSha']); const commitUrl = metadataString(outcomes, ['commit_url', 'commitUrl']); const tests = asMetadataRecord(outcomes?.tests) as { passed?: number; failed?: number; skipped?: number } | null; + const showStatusUpdatesPanel = + statusUpdates.length > 0 || + (statusUpdatesApplied ?? 0) > 0 || + statusBuffered; + const showUpdatesInOutcomes = + showStatusUpdatesPanel && + (!activeArtifact || eventName.includes('status_updates')); const hasAny = prUrl || commitSha || tests || - statusUpdates.length > 0 || - (statusUpdatesApplied ?? 0) > 0 || - statusBuffered; + showUpdatesInOutcomes; if (!hasAny) return null; return (
- Updates & outcomes + {showUpdatesInOutcomes ? 'Updates & outcomes' : 'Outcomes'}
- {(statusUpdates.length > 0 || (statusUpdatesApplied ?? 0) > 0 || statusBuffered) && ( + {showUpdatesInOutcomes && (- {workstreamHeading} + {agentPersona ? ( +
+ {agentPersona.displayLabel}
- {agentPersona ? ( -- {agentPersona.displayLabel} -
- ) : null} -{rowTitleDisplay}
diff --git a/dashboard/src/data/mockData.ts b/dashboard/src/data/mockData.ts index e5a6b514..abfc01da 100644 --- a/dashboard/src/data/mockData.ts +++ b/dashboard/src/data/mockData.ts @@ -6,6 +6,8 @@ export const createMockData = (): LiveData => { new Date(now.getTime() - m * 60 * 1000).toISOString(); const minusHours = (h: number) => new Date(now.getTime() - h * 60 * 60 * 1000).toISOString(); + const minusDays = (d: number) => + new Date(now.getTime() - d * 24 * 60 * 60 * 1000).toISOString(); return { connection: 'connected', @@ -28,6 +30,8 @@ export const createMockData = (): LiveData => { { parentId: 'run-200', childId: 'run-202' }, { parentId: 'run-200', childId: 'run-203' }, { parentId: 'run-300', childId: 'run-301' }, + { parentId: 'run-300', childId: 'run-302' }, + { parentId: 'run-300', childId: 'run-303' }, ], nodes: [ { @@ -319,27 +323,27 @@ export const createMockData = (): LiveData => { title: 'Directory Submissions & External References', agentId: 'ops', agentName: 'Ops', - status: 'queued', - progress: 8, + status: 'running', + progress: 36, initiativeId: 'init-3', workstreamId: null, groupId: 'init-3', groupLabel: 'Directory Submissions & External References', - startedAt: minusHours(2), - updatedAt: minusMinutes(11), - lastEventAt: minusMinutes(11), - lastEventSummary: 'Queued while waiting for vendor API credentials.', - blockers: ['Awaiting API credentials for two external data vendors'], - phase: 'blocked', - state: 'stale', - blockerReason: 'Credential handshake incomplete for enrichment vendors.', - eta: 'Pending access', - checkpointCount: 2, + startedAt: minusHours(3), + updatedAt: minusMinutes(5), + lastEventAt: minusMinutes(5), + lastEventSummary: 'Multi-lane pipeline active: import retries, QA verification, and outreach copy drafting.', + blockers: ['One vendor lane still rate-limited; recovery in progress'], + phase: 'execution', + state: 'running', + blockerReason: 'Partial dependency degradation on one vendor lane.', + eta: '42m', + checkpointCount: 8, runtimeClient: 'openclaw', runtimeLabel: 'OpenClaw Intake', runtimeProvider: 'openclaw', instanceId: 'instance-openclaw-08', - lastHeartbeatAt: minusMinutes(11), + lastHeartbeatAt: minusMinutes(2), }, { id: 'run-301', @@ -369,6 +373,62 @@ export const createMockData = (): LiveData => { instanceId: 'instance-openclaw-09', lastHeartbeatAt: minusMinutes(1), }, + { + id: 'run-302', + parentId: 'run-300', + runId: 'run-302', + title: 'Reference verification QA lane', + agentId: 'kimi', + agentName: 'Kimi', + status: 'running', + progress: 58, + initiativeId: 'init-3', + workstreamId: 'ws-directory-qa', + groupId: 'init-3', + groupLabel: 'Directory Submissions & External References', + startedAt: minusHours(2), + updatedAt: minusMinutes(5), + lastEventAt: minusMinutes(5), + lastEventSummary: 'Citation verification batch completed; QA memo and mismatch ledger attached.', + blockers: [], + phase: 'execution', + state: 'running', + eta: '18m', + checkpointCount: 5, + runtimeClient: 'codex', + runtimeLabel: 'Codex QA Worker', + runtimeProvider: 'codex', + instanceId: 'instance-codex-09', + lastHeartbeatAt: minusMinutes(1), + }, + { + id: 'run-303', + parentId: 'run-300', + runId: 'run-303', + title: 'External partner outreach copy', + agentId: 'mark', + agentName: 'Mark', + status: 'running', + progress: 41, + initiativeId: 'init-3', + workstreamId: 'ws-directory-outreach', + groupId: 'init-3', + groupLabel: 'Directory Submissions & External References', + startedAt: minusHours(2), + updatedAt: minusMinutes(8), + lastEventAt: minusMinutes(8), + lastEventSummary: 'Outreach sequence draft in progress with two channel variants.', + blockers: [], + phase: 'execution', + state: 'running', + eta: '24m', + checkpointCount: 4, + runtimeClient: 'openclaw', + runtimeLabel: 'OpenClaw Content Worker', + runtimeProvider: 'openclaw', + instanceId: 'instance-openclaw-13', + lastHeartbeatAt: minusMinutes(2), + }, { id: 'run-400', parentId: null, @@ -564,6 +624,133 @@ export const createMockData = (): LiveData => { run_id: 'slice-run-102', }, }, + { + id: 'activity-225', + type: 'artifact_created', + title: 'Artifact created: reference QA packet', + description: 'Published mismatch ledger and verification memo for the latest reference batch.', + agentId: 'kimi', + agentName: 'Kimi', + requesterAgentId: 'ops', + requesterAgentName: 'Ops', + executorAgentId: 'kimi', + executorAgentName: 'Kimi', + runId: 'run-302', + initiativeId: 'init-3', + timestamp: minusMinutes(5), + metadata: { + event: 'artifact_registered', + event_name: 'artifact_registered', + source: 'agent', + parsed_status: 'completed', + outcomes: { + artifact_count: 2, + tests: { passed: 14, failed: 0, skipped: 1 }, + task_updates: 2, + }, + task_updates: [ + { title: 'Run citation verification across 120 references', status: 'completed' }, + { title: 'Publish mismatch ledger for reviewer approval', status: 'completed' }, + ], + artifacts: [ + { + id: 'artifact-dir-qa-1', + type: 'report', + title: 'Reference verification memo', + url: null, + }, + { + id: 'artifact-dir-qa-2', + type: 'spreadsheet', + title: 'Citation mismatch ledger', + url: null, + }, + ], + }, + }, + { + id: 'activity-226', + type: 'delegation', + title: 'Dispatch: partner outreach copy lane', + description: 'Orchestrator launched a copy lane to draft partner outreach and handoff templates.', + agentId: 'orgx', + agentName: 'OrgX', + requesterAgentId: 'orgx', + requesterAgentName: 'OrgX', + executorAgentId: 'mark', + executorAgentName: 'Mark', + runId: 'run-300', + initiativeId: 'init-3', + timestamp: minusMinutes(9), + metadata: { + event: 'autopilot_slice_dispatched', + event_name: 'autopilot_slice_dispatched', + source: 'orchestrator', + parsed_status: 'running', + run_id: 'slice-run-112', + dispatch_selection_reason: + 'Reference verification can proceed in parallel with outreach preparation.', + }, + }, + { + id: 'activity-227', + type: 'run_started', + title: 'Slice started: outreach sequence draft', + description: 'Mark began drafting outreach sequence copy for external partners.', + agentId: 'mark', + agentName: 'Mark', + requesterAgentId: 'orgx', + requesterAgentName: 'OrgX', + executorAgentId: 'mark', + executorAgentName: 'Mark', + runId: 'run-303', + initiativeId: 'init-3', + timestamp: minusMinutes(8), + metadata: { + event: 'autopilot_slice_started', + event_name: 'autopilot_slice_started', + source: 'agent', + parsed_status: 'running', + run_id: 'slice-run-112', + }, + }, + { + id: 'activity-228', + type: 'artifact_created', + title: 'Artifact created: outreach copy sequence', + description: 'Drafted email + LinkedIn outreach variants and handoff checklist.', + agentId: 'mark', + agentName: 'Mark', + requesterAgentId: 'mark', + requesterAgentName: 'Mark', + executorAgentId: 'mark', + executorAgentName: 'Mark', + runId: 'run-303', + initiativeId: 'init-3', + timestamp: minusMinutes(6), + metadata: { + event: 'artifact_registered', + event_name: 'artifact_registered', + source: 'agent', + parsed_status: 'completed', + outcomes: { + artifact_count: 1, + tests: { passed: 8, failed: 0, skipped: 0 }, + }, + task_updates: [ + { title: 'Produce 2 outreach channel variants', status: 'completed' }, + { title: 'Attach partner-ready handoff checklist', status: 'completed' }, + ], + artifacts: [ + { + id: 'artifact-dir-outreach-1', + type: 'brief', + title: 'Partner outreach sequence v1', + url: null, + }, + ], + }, + }, { id: 'activity-205', type: 'decision_requested', @@ -791,6 +978,73 @@ export const createMockData = (): LiveData => { blocked_reason: 'Credentials not provisioned in secret manager.', }, }, + { + id: 'activity-230', + type: 'milestone_completed', + title: 'Milestone completed: readability foundation', + description: 'Baseline readability hierarchy shipped and adopted in activity and mission panels.', + agentId: 'dana', + agentName: 'Dana', + requesterAgentId: 'orgx', + requesterAgentName: 'OrgX', + executorAgentId: 'dana', + executorAgentName: 'Dana', + runId: 'run-201', + initiativeId: 'init-2', + timestamp: minusDays(2), + metadata: { + event: 'milestone_completed', + event_name: 'milestone_completed', + source: 'agent', + parsed_status: 'completed', + outcomes: { + artifact_count: 1, + tests: { passed: 22, failed: 0, skipped: 3 }, + }, + artifacts: [ + { + id: 'artifact-ux-activity-legacy', + type: 'design', + title: 'Readability hierarchy baseline', + url: null, + }, + ], + }, + }, + { + id: 'activity-231', + type: 'artifact_created', + title: 'Artifact created: executive notes and next-up alignment', + description: 'You captured final guidance so completed work maps cleanly to what starts next.', + agentId: 'main', + agentName: 'You', + requesterAgentId: 'main', + requesterAgentName: 'You', + executorAgentId: 'main', + executorAgentName: 'You', + runId: 'run-500', + initiativeId: 'init-4', + timestamp: minusDays(1), + metadata: { + event: 'artifact_registered', + event_name: 'artifact_registered', + source: 'user', + parsed_status: 'completed', + outcomes: { + artifact_count: 1, + task_updates: 1, + }, + task_updates: [{ title: 'Connect closeout outputs to next-up backlog', status: 'completed' }], + artifacts: [ + { + id: 'artifact-revenue-7', + type: 'brief', + title: 'Executive closeout notes', + url: null, + }, + ], + }, + }, { id: 'activity-219', type: 'run_started', @@ -1874,6 +2128,99 @@ export const createMockData = (): LiveData => { completedTasks: 1, }, }, + { + id: 'slice-run-111', + sliceRunId: 'slice-run-111', + runId: 'run-302', + initiativeId: 'init-3', + workstreamId: 'ws-directory-qa', + workstreamTitle: 'Reference verification QA lane', + taskIds: ['task-dir-qa-1', 'task-dir-qa-2'], + milestoneIds: ['mile-dir-2'], + status: 'running', + statusExplainer: 'Verification memo published; reconciling final citation mismatches.', + primaryAction: 'review_output', + hasArtifact: true, + artifactCount: 2, + artifacts: [ + { + id: 'artifact-dir-qa-1', + type: 'report', + title: 'Reference verification memo', + url: null, + createdAt: minusMinutes(5), + }, + { + id: 'artifact-dir-qa-2', + type: 'spreadsheet', + title: 'Citation mismatch ledger', + url: null, + createdAt: minusMinutes(5), + }, + ], + decisionCount: 0, + blockingDecisionCount: 0, + decisionOptions: [], + sourceClient: 'codex', + runtimeState: 'active', + startedAt: minusHours(2), + updatedAt: minusMinutes(5), + completedAt: null, + failedAt: null, + archivedAt: null, + lastEventAt: minusMinutes(5), + lastEventSummary: 'QA packet shipped; final mismatch reconciliation in progress.', + correlationId: 'run-302', + confidence: 'high', + scope: 'task', + scopeProgress: { + totalTasks: 4, + completedTasks: 2, + }, + }, + { + id: 'slice-run-112', + sliceRunId: 'slice-run-112', + runId: 'run-303', + initiativeId: 'init-3', + workstreamId: 'ws-directory-outreach', + workstreamTitle: 'External partner outreach copy', + taskIds: ['task-dir-outreach-1', 'task-dir-outreach-2'], + milestoneIds: ['mile-dir-3'], + status: 'running', + statusExplainer: 'Draft sequence underway with channel variants attached for quick review.', + primaryAction: 'review_output', + hasArtifact: true, + artifactCount: 1, + artifacts: [ + { + id: 'artifact-dir-outreach-1', + type: 'brief', + title: 'Partner outreach sequence v1', + url: null, + createdAt: minusMinutes(6), + }, + ], + decisionCount: 0, + blockingDecisionCount: 0, + decisionOptions: [], + sourceClient: 'openclaw', + runtimeState: 'active', + startedAt: minusHours(2), + updatedAt: minusMinutes(6), + completedAt: null, + failedAt: null, + archivedAt: null, + lastEventAt: minusMinutes(6), + lastEventSummary: 'Email + LinkedIn variants drafted; QA polish remaining.', + correlationId: 'run-303', + confidence: 'medium', + scope: 'task', + scopeProgress: { + totalTasks: 3, + completedTasks: 1, + }, + }, ], runtimeInstances: [ { @@ -1960,6 +2307,48 @@ export const createMockData = (): LiveData => { lastMessage: 'Vendor cooldown window reopened.', metadata: { retryAttempt: 3, vendor: 'clearbit-sandbox' }, }, + { + id: 'instance-codex-09', + sourceClient: 'codex', + displayName: 'Codex QA Worker', + providerLogo: 'codex', + state: 'active', + runId: 'run-302', + correlationId: 'run-302', + initiativeId: 'init-3', + workstreamId: 'ws-directory-qa', + taskId: 'task-dir-qa-2', + agentId: 'kimi', + agentName: 'Kimi', + phase: 'execution', + progressPct: 58, + currentTask: 'Reconciling citation mismatches after verification pass', + lastHeartbeatAt: minusMinutes(1), + lastEventAt: minusMinutes(1), + lastMessage: 'QA memo published; validating final mismatch set.', + metadata: { artifactIds: ['artifact-dir-qa-1', 'artifact-dir-qa-2'] }, + }, + { + id: 'instance-openclaw-13', + sourceClient: 'openclaw', + displayName: 'OpenClaw Content Worker', + providerLogo: 'openclaw', + state: 'active', + runId: 'run-303', + correlationId: 'run-303', + initiativeId: 'init-3', + workstreamId: 'ws-directory-outreach', + taskId: 'task-dir-outreach-2', + agentId: 'mark', + agentName: 'Mark', + phase: 'execution', + progressPct: 41, + currentTask: 'Drafting partner outreach sequence', + lastHeartbeatAt: minusMinutes(2), + lastEventAt: minusMinutes(2), + lastMessage: 'Outreach variants drafted; preparing QA polish.', + metadata: { artifactId: 'artifact-dir-outreach-1' }, + }, { id: 'instance-orgx-01', sourceClient: 'api', diff --git a/dashboard/src/hooks/useNextUpQueue.ts b/dashboard/src/hooks/useNextUpQueue.ts index d8f34ebf..494c50a5 100644 --- a/dashboard/src/hooks/useNextUpQueue.ts +++ b/dashboard/src/hooks/useNextUpQueue.ts @@ -161,48 +161,247 @@ function normalizeTransportFailure(err: unknown, fallback: string): string { function buildDemoQueueResponse(initiativeId: string | null): NextUpQueueResponse { const nowIso = new Date().toISOString(); + const minusMinutes = (minutes: number) => + new Date(Date.now() - minutes * 60_000).toISOString(); + const autoState = ( + status: 'running' | 'stopping' | 'stopped', + updatedAt: string, + input?: { + activeTaskId?: string | null; + activeRunId?: string | null; + stopReason?: 'budget_exhausted' | 'blocked' | 'completed' | 'stopped' | 'error' | null; + maxParallelSlices?: number; + parallelMode?: 'iwmt'; + } + ): NonNullable