feat(governance): 新增 12-Agent War Room 讀回
This commit is contained in:
@@ -39,6 +39,7 @@ import { StatusOrb } from '@/components/ui/status-orb'
|
||||
import { AgentActivityConstellation } from '@/components/governance/agent-activity-constellation'
|
||||
import {
|
||||
apiClient,
|
||||
type AiAgent12AgentWarRoomSnapshot,
|
||||
type AiAgentCandidateOperationDryRunEvidenceSnapshot,
|
||||
type AiAgentCriticReviewerResultCaptureSnapshot,
|
||||
type AiAgentDeploymentLayoutSnapshot,
|
||||
@@ -457,6 +458,7 @@ export function AutomationInventoryTab() {
|
||||
const [observabilityMatrix, setObservabilityMatrix] = useState<ObservabilityContractMatrixSnapshot | null>(null)
|
||||
const [providerRouteMatrix, setProviderRouteMatrix] = useState<AiProviderRouteMatrixSnapshot | null>(null)
|
||||
const [deploymentLayout, setDeploymentLayout] = useState<AiAgentDeploymentLayoutSnapshot | null>(null)
|
||||
const [warRoom, setWarRoom] = useState<AiAgent12AgentWarRoomSnapshot | null>(null)
|
||||
const [proactiveOperations, setProactiveOperations] = useState<AiAgentProactiveOperationsContractSnapshot | null>(null)
|
||||
const [interactionLearningProof, setInteractionLearningProof] = useState<AiAgentInteractionLearningProofSnapshot | null>(null)
|
||||
const [liveReadModelGate, setLiveReadModelGate] = useState<AiAgentLiveReadModelGateSnapshot | null>(null)
|
||||
@@ -535,6 +537,7 @@ export function AutomationInventoryTab() {
|
||||
apiClient.getObservabilityContractMatrix(),
|
||||
apiClient.getAiProviderRouteMatrix(),
|
||||
apiClient.getAiAgentDeploymentLayout(),
|
||||
apiClient.getAiAgent12AgentWarRoom(),
|
||||
apiClient.getAiAgentProactiveOperationsContract(),
|
||||
apiClient.getAiAgentInteractionLearningProof(),
|
||||
apiClient.getAiAgentLiveReadModelGate(),
|
||||
@@ -612,6 +615,7 @@ export function AutomationInventoryTab() {
|
||||
observabilityMatrixResult,
|
||||
providerRouteMatrixResult,
|
||||
deploymentLayoutResult,
|
||||
warRoomResult,
|
||||
proactiveOperationsResult,
|
||||
interactionLearningProofResult,
|
||||
liveReadModelGateResult,
|
||||
@@ -686,6 +690,7 @@ export function AutomationInventoryTab() {
|
||||
setObservabilityMatrix(observabilityMatrixResult.status === 'fulfilled' ? observabilityMatrixResult.value : null)
|
||||
setProviderRouteMatrix(providerRouteMatrixResult.status === 'fulfilled' ? providerRouteMatrixResult.value : null)
|
||||
setDeploymentLayout(deploymentLayoutResult.status === 'fulfilled' ? deploymentLayoutResult.value : null)
|
||||
setWarRoom(warRoomResult.status === 'fulfilled' ? warRoomResult.value : null)
|
||||
setProactiveOperations(proactiveOperationsResult.status === 'fulfilled' ? proactiveOperationsResult.value : null)
|
||||
setInteractionLearningProof(interactionLearningProofResult.status === 'fulfilled' ? interactionLearningProofResult.value : null)
|
||||
setLiveReadModelGate(liveReadModelGateResult.status === 'fulfilled' ? liveReadModelGateResult.value : null)
|
||||
@@ -758,6 +763,7 @@ export function AutomationInventoryTab() {
|
||||
observabilityMatrixResult,
|
||||
providerRouteMatrixResult,
|
||||
deploymentLayoutResult,
|
||||
warRoomResult,
|
||||
proactiveOperationsResult,
|
||||
interactionLearningProofResult,
|
||||
liveReadModelGateResult,
|
||||
@@ -883,6 +889,19 @@ export function AutomationInventoryTab() {
|
||||
.slice(0, 12)
|
||||
}, [deploymentLayout])
|
||||
|
||||
const visibleWarRoomRoles = useMemo(() => {
|
||||
if (!warRoom) return []
|
||||
const riskPriority = { critical: 0, high: 1, medium: 2, low: 3 } as Record<string, number>
|
||||
return [...warRoom.agent_roles]
|
||||
.sort((a, b) => {
|
||||
const riskLeft = riskPriority[a.risk_tier] ?? 4
|
||||
const riskRight = riskPriority[b.risk_tier] ?? 4
|
||||
if (riskLeft !== riskRight) return riskLeft - riskRight
|
||||
return a.agent_id.localeCompare(b.agent_id)
|
||||
})
|
||||
.slice(0, 12)
|
||||
}, [warRoom])
|
||||
|
||||
const visibleDelegableCapabilities = useMemo(() => {
|
||||
if (!proactiveOperations) return []
|
||||
const riskPriority = { critical: 0, high: 1, medium: 2, low: 3 } as Record<string, number>
|
||||
@@ -2056,7 +2075,7 @@ export function AutomationInventoryTab() {
|
||||
)
|
||||
}
|
||||
|
||||
if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !proactiveOperations || !interactionLearningProof || !liveReadModelGate || !redisDryRunGate || !learningWritebackPackage || !telegramReceiptPackage || !ownerApprovedLearningDryRun || !runtimeWriteGateReview || !postWriteVerifierPackage || !runtimeVerifierEvidenceReview || !reportAutomationReview || !reportStatusBoard || !reportRuntimeReadiness || !reportRuntimeDryRun || !reportRuntimeFixtureReadback || !runtimeWorkerShadowGate || !operationPermissionModel || !candidateOperationDryRunEvidence || !taskResultAuditTrail || !matchedPlaybookLearningGap || !criticReviewerResultCapture || !ownerApprovedResultCaptureDryRun || !ownerApprovedResultCaptureReadback || !runtimeReadbackApprovalPackage || !runtimeReadbackImplementationReview || !reportLiveDeliveryApprovalPackage || !runtimeReadbackFixtureApproval || !runtimeReadbackPromotionGate || !ownerApprovedFixturePromotionGate || !canonicalRuntimeReadbackOwnerAcceptance || !failureReceiptNoSendReplay || !reviewerQueueNoWriteReadback || !resultCaptureNoWriteReadback || !resultCapturePromotionApprovalGate || !ownerApprovedResultCapturePromotionDryRun || !resultCaptureWriteGateReview || !resultCaptureWriterImplementationReview || !resultCaptureWriterDryRunFixture || !resultCaptureWriterDryRunReadback || !resultCaptureOwnerPromotionReview || !resultCaptureOwnerApprovedExecutionRehearsal || !resultCaptureOwnerAcceptanceMaintenanceGate || !resultCaptureOwnerAcceptanceReadbackPreflightHold || !resultCaptureOwnerApprovedPreflightReleasePackage || !resultCaptureOwnerApprovedReleaseReadinessReadback || !resultCaptureOwnerReleaseApprovalGate || !resultCapturePostReleaseVerifierRollbackGate || !resultCaptureFinalReleaseCandidateReadback || !resultCaptureReleaseAuthorizationHold || !resultCaptureReleaseAuthorizationReadbackGate || !resultCaptureReleaseVerifierPreflightGate || !resultCaptureReleaseVerifierOwnerReviewPacket || !resultCaptureReleaseDecisionHold || !resultCaptureReleaseDecisionReadback || !resultCaptureReleaseDecisionNextHandoff || !resultCaptureReleaseDecisionInputPrep || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) {
|
||||
if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !warRoom || !proactiveOperations || !interactionLearningProof || !liveReadModelGate || !redisDryRunGate || !learningWritebackPackage || !telegramReceiptPackage || !ownerApprovedLearningDryRun || !runtimeWriteGateReview || !postWriteVerifierPackage || !runtimeVerifierEvidenceReview || !reportAutomationReview || !reportStatusBoard || !reportRuntimeReadiness || !reportRuntimeDryRun || !reportRuntimeFixtureReadback || !runtimeWorkerShadowGate || !operationPermissionModel || !candidateOperationDryRunEvidence || !taskResultAuditTrail || !matchedPlaybookLearningGap || !criticReviewerResultCapture || !ownerApprovedResultCaptureDryRun || !ownerApprovedResultCaptureReadback || !runtimeReadbackApprovalPackage || !runtimeReadbackImplementationReview || !reportLiveDeliveryApprovalPackage || !runtimeReadbackFixtureApproval || !runtimeReadbackPromotionGate || !ownerApprovedFixturePromotionGate || !canonicalRuntimeReadbackOwnerAcceptance || !failureReceiptNoSendReplay || !reviewerQueueNoWriteReadback || !resultCaptureNoWriteReadback || !resultCapturePromotionApprovalGate || !ownerApprovedResultCapturePromotionDryRun || !resultCaptureWriteGateReview || !resultCaptureWriterImplementationReview || !resultCaptureWriterDryRunFixture || !resultCaptureWriterDryRunReadback || !resultCaptureOwnerPromotionReview || !resultCaptureOwnerApprovedExecutionRehearsal || !resultCaptureOwnerAcceptanceMaintenanceGate || !resultCaptureOwnerAcceptanceReadbackPreflightHold || !resultCaptureOwnerApprovedPreflightReleasePackage || !resultCaptureOwnerApprovedReleaseReadinessReadback || !resultCaptureOwnerReleaseApprovalGate || !resultCapturePostReleaseVerifierRollbackGate || !resultCaptureFinalReleaseCandidateReadback || !resultCaptureReleaseAuthorizationHold || !resultCaptureReleaseAuthorizationReadbackGate || !resultCaptureReleaseVerifierPreflightGate || !resultCaptureReleaseVerifierOwnerReviewPacket || !resultCaptureReleaseDecisionHold || !resultCaptureReleaseDecisionReadback || !resultCaptureReleaseDecisionNextHandoff || !resultCaptureReleaseDecisionInputPrep || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) {
|
||||
return (
|
||||
<div style={{ padding: 20 }}>
|
||||
<GlassCard variant="subtle" padding="lg">
|
||||
@@ -3519,6 +3538,34 @@ export function AutomationInventoryTab() {
|
||||
serviceHealthNotificationPolicy.display_redaction_contract.conversation_transcript_display_allowed === false
|
||||
&& serviceHealthNotificationPolicy.display_redaction_contract.redaction_required === true
|
||||
)
|
||||
const warRoomOverall = warRoom.program_status.overall_completion_percent
|
||||
const warRoomCompletedReviews = warRoom.rollups.read_only_review_completed_count
|
||||
const warRoomRoleCount = warRoom.rollups.agent_role_count
|
||||
const warRoomBatchCount = warRoom.rollups.subagent_batch_count
|
||||
const warRoomBatchLimit = warRoom.rollups.subagent_batch_limit
|
||||
const warRoomWorkUnits = warRoom.rollups.total_work_units
|
||||
const warRoomApprovals = warRoom.rollups.approval_required_total
|
||||
const warRoomBlockers = warRoom.rollups.blocker_total
|
||||
const warRoomMarketCandidates = warRoom.rollups.market_refresh_candidate_count
|
||||
const warRoomReportCadences = (
|
||||
warRoom.rollups.daily_report_required_count
|
||||
+ warRoom.rollups.weekly_report_required_count
|
||||
+ warRoom.rollups.monthly_report_required_count
|
||||
)
|
||||
const warRoomLiveWrites = (
|
||||
warRoom.rollups.live_write_count
|
||||
+ warRoom.rollups.telegram_send_count
|
||||
+ warRoom.rollups.bot_api_call_count
|
||||
+ warRoom.rollups.production_write_count
|
||||
+ warRoom.rollups.paid_api_call_count
|
||||
+ warRoom.rollups.sdk_install_count
|
||||
+ warRoom.rollups.secret_read_count
|
||||
+ warRoom.rollups.destructive_operation_count
|
||||
)
|
||||
const warRoomRedactionLocked = (
|
||||
warRoom.display_redaction_contract.conversation_transcript_display_allowed === false
|
||||
&& warRoom.display_redaction_contract.redaction_required === true
|
||||
)
|
||||
const backlogProgressPercent = backlog.progress_summary.overall_percent
|
||||
const explicitApprovalItemCount = backlog.item_approval_boundary_rollup.items_requiring_explicit_approval.length
|
||||
const taskBoundaryCount = snapshot.task_approval_boundary_rollup.total_tasks
|
||||
@@ -3788,6 +3835,123 @@ export function AutomationInventoryTab() {
|
||||
]}
|
||||
/>
|
||||
|
||||
<GlassCard variant="subtle" padding="md">
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 13, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0 }}>
|
||||
<Layers3 size={15} style={{ color: '#d97757' }} />
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 14, fontWeight: 700, color: '#141413' }}>
|
||||
{t('warRoom.title')}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, justifyContent: 'flex-end' }}>
|
||||
<Chip
|
||||
value={t('warRoom.source', {
|
||||
generated: formatDateTime(warRoom.generated_at),
|
||||
current: warRoom.program_status.current_task_id,
|
||||
next: warRoom.program_status.next_task_id,
|
||||
})}
|
||||
muted
|
||||
/>
|
||||
<Chip value={t('warRoom.runtime', { value: warRoom.program_status.runtime_authority })} muted />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p style={{ margin: 0, fontFamily: "'DM Mono', monospace", fontSize: 11, lineHeight: 1.55, color: '#5c5a55', overflowWrap: 'anywhere' }}>
|
||||
{warRoom.program_status.status_note}
|
||||
</p>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(128px, 1fr))', gap: 10 }} className="automation-inventory-live-read-kpi-grid">
|
||||
<MetricCard label={t('warRoom.metrics.overall')} value={`${warRoomOverall}%`} tone="warn" icon={<Gauge size={16} />} />
|
||||
<MetricCard label={t('warRoom.metrics.reviews')} value={`${warRoomCompletedReviews}/${warRoomRoleCount}`} tone="ok" icon={<ShieldCheck size={16} />} />
|
||||
<MetricCard label={t('warRoom.metrics.batches')} value={`${warRoomBatchCount}×${warRoomBatchLimit}`} tone="neutral" icon={<Layers3 size={16} />} />
|
||||
<MetricCard label={t('warRoom.metrics.workUnits')} value={warRoomWorkUnits} tone="neutral" icon={<FileText size={16} />} />
|
||||
<MetricCard label={t('warRoom.metrics.approvals')} value={warRoomApprovals} tone="warn" icon={<ShieldAlert size={16} />} />
|
||||
<MetricCard label={t('warRoom.metrics.blockers')} value={warRoomBlockers} tone="danger" icon={<AlertTriangle size={16} />} />
|
||||
<MetricCard label={t('warRoom.metrics.market')} value={warRoomMarketCandidates} tone="warn" icon={<Target size={16} />} />
|
||||
<MetricCard label={t('warRoom.metrics.liveWrites')} value={warRoomLiveWrites} tone={warRoomLiveWrites === 0 ? 'ok' : 'danger'} icon={<BellOff size={16} />} />
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))', gap: 10 }}>
|
||||
<div style={{ padding: 10, border: '0.5px solid #d7c7a1', borderRadius: 7, background: '#fff', minWidth: 0 }}>
|
||||
<SmallLabel>{t('warRoom.coordinationTitle')}</SmallLabel>
|
||||
<p style={{ margin: '6px 0 8px', fontFamily: "'DM Mono', monospace", fontSize: 10, lineHeight: 1.5, color: '#5c5a55', overflowWrap: 'anywhere' }}>
|
||||
{warRoom.coordination_model.summary}
|
||||
</p>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={t('warRoom.labels.arbiter', { value: warRoom.coordination_model.arbiter })} />
|
||||
<Chip value={t('warRoom.labels.memory', { value: warRoom.coordination_model.memory_owner })} muted />
|
||||
<Chip value={t('warRoom.labels.replay', { value: warRoom.coordination_model.replay_owner })} muted />
|
||||
<Chip value={t('warRoom.labels.reports', { value: String(warRoomReportCadences) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 10, border: '0.5px solid #d7c7a1', borderRadius: 7, background: '#fff', minWidth: 0 }}>
|
||||
<SmallLabel>{t('warRoom.telegramTitle')}</SmallLabel>
|
||||
<p style={{ margin: '6px 0 8px', fontFamily: "'DM Mono', monospace", fontSize: 10, lineHeight: 1.5, color: '#5c5a55', overflowWrap: 'anywhere' }}>
|
||||
{warRoom.telegram_contract.summary}
|
||||
</p>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={t('warRoom.labels.directSend', { value: String(warRoom.telegram_contract.direct_send_allowed) })} />
|
||||
<Chip value={t('warRoom.labels.botApi', { value: String(warRoom.telegram_contract.bot_api_call_allowed) })} muted />
|
||||
<Chip value={t('warRoom.labels.dedup', { value: String(warRoom.telegram_contract.dedup_required) })} muted />
|
||||
<Chip value={t('warRoom.labels.redaction', { value: String(warRoomRedactionLocked) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SmallLabel>{t('warRoom.rolesTitle')}</SmallLabel>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
||||
{visibleWarRoomRoles.map(role => {
|
||||
const roleTone = role.risk_tier === 'critical' ? 'danger' : role.risk_tier === 'high' ? 'warn' : 'neutral'
|
||||
const roleColor = toneColor(roleTone)
|
||||
return (
|
||||
<div key={role.agent_id} style={{ padding: 10, border: `0.5px solid ${roleColor}55`, borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 7, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, alignItems: 'center', minWidth: 0 }}>
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 12, fontWeight: 700, color: '#141413', overflowWrap: 'anywhere' }}>
|
||||
{role.display_name}
|
||||
</span>
|
||||
<Chip value={role.risk_tier} muted={role.risk_tier !== 'critical'} />
|
||||
</div>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
||||
{role.war_room_role}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={role.primary_agent} muted />
|
||||
<Chip value={t('warRoom.labels.workUnits', { value: String(role.work_units) })} muted />
|
||||
<Chip value={t('warRoom.labels.approvals', { value: String(role.approval_required_count) })} muted />
|
||||
<Chip value={t('warRoom.labels.blockers', { value: String(role.blocker_count) })} muted />
|
||||
<Chip value={t('warRoom.labels.liveWrites', { value: String(role.live_write_count) })} muted />
|
||||
<Chip value={t('warRoom.labels.telegramSends', { value: String(role.telegram_send_count) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }}>
|
||||
<MiniBar
|
||||
label={t('warRoom.report.daily')}
|
||||
value={warRoom.reporting_contract.daily.required ? 100 : 0}
|
||||
detail={warRoom.reporting_contract.daily.delivery_mode}
|
||||
tone="ok"
|
||||
/>
|
||||
<MiniBar
|
||||
label={t('warRoom.report.weekly')}
|
||||
value={warRoom.reporting_contract.weekly.required ? 100 : 0}
|
||||
detail={warRoom.reporting_contract.weekly.delivery_mode}
|
||||
tone="ok"
|
||||
/>
|
||||
<MiniBar
|
||||
label={t('warRoom.report.monthly')}
|
||||
value={warRoom.reporting_contract.monthly.required ? 100 : 0}
|
||||
detail={warRoom.reporting_contract.monthly.delivery_mode}
|
||||
tone="warn"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</GlassCard>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1.05fr) minmax(0, 0.95fr)', gap: 12 }} className="automation-inventory-command-grid">
|
||||
<GlassCard variant="subtle" padding="md">
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 13, minWidth: 0 }}>
|
||||
|
||||
Reference in New Issue
Block a user