|
|
|
|
@@ -112,12 +112,43 @@ const PUBLIC_TEXT_HOST_ALIASES: Record<string, string> = {
|
|
|
|
|
|
|
|
|
|
const PRIVATE_LAN_PREFIX_PATTERN = ['192', '168', '0'].join('\\.')
|
|
|
|
|
const PRIVATE_LAN_TEXT_PATTERN = new RegExp(`(?:https?:\\/\\/)?${PRIVATE_LAN_PREFIX_PATTERN}\\.(\\d{1,3})(?::(\\d{1,5}))?`, 'g')
|
|
|
|
|
const PUBLIC_TEXT_REPLACEMENTS: Array<[RegExp, string]> = [
|
|
|
|
|
[/工作視窗/g, '內部協作環境'],
|
|
|
|
|
[/對話內容/g, '內部協作內容'],
|
|
|
|
|
[/批准!繼續/g, '內部短訊指令'],
|
|
|
|
|
[/批准!/g, '內部短訊指令'],
|
|
|
|
|
[/In app browser/gi, '內部瀏覽器狀態'],
|
|
|
|
|
[/My request for Codex/gi, '內部協作請求'],
|
|
|
|
|
[/browser_context/gi, 'redacted_browser_context'],
|
|
|
|
|
[/codex_user_message/gi, 'redacted_user_message'],
|
|
|
|
|
[/prompt_text/gi, 'redacted_prompt_text'],
|
|
|
|
|
[/raw prompt/gi, '未脫敏提示內容'],
|
|
|
|
|
[/raw_prompt/gi, 'redacted_prompt'],
|
|
|
|
|
[/private reasoning/gi, '私有推理內容'],
|
|
|
|
|
[/private_reasoning/gi, 'redacted_private_reasoning'],
|
|
|
|
|
[/chain of thought/gi, '推理鏈內容'],
|
|
|
|
|
[/chain_of_thought/gi, 'redacted_chain_of_thought'],
|
|
|
|
|
[/raw Telegram payload/gi, '原始 Telegram 載荷'],
|
|
|
|
|
[/raw_telegram_payload/gi, 'redacted_telegram_payload'],
|
|
|
|
|
[/raw tool output/gi, '原始工具輸出'],
|
|
|
|
|
[/raw_tool_output/gi, 'redacted_tool_output'],
|
|
|
|
|
[/raw payload/gi, '原始載荷'],
|
|
|
|
|
[/raw_payload/gi, 'redacted_payload'],
|
|
|
|
|
[/authorization header/gi, '授權標頭'],
|
|
|
|
|
[/authorization_header/gi, 'redacted_authorization_header'],
|
|
|
|
|
[/secret value/gi, '機密明文'],
|
|
|
|
|
[/secret_value/gi, 'redacted_secret_value'],
|
|
|
|
|
[/work window transcript/gi, '內部協作逐字稿'],
|
|
|
|
|
[/work_window_transcript/gi, 'redacted_work_window_transcript'],
|
|
|
|
|
[/internal collaboration transcript/gi, '內部協作逐字稿'],
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
function redactPublicText(value: string): string {
|
|
|
|
|
return value.replace(PRIVATE_LAN_TEXT_PATTERN, (_match, octet: string, port: string | undefined) => {
|
|
|
|
|
const redactedLan = value.replace(PRIVATE_LAN_TEXT_PATTERN, (_match, octet: string, port: string | undefined) => {
|
|
|
|
|
if (port) return PUBLIC_TEXT_ENDPOINT_ALIASES[`${octet}:${port}`] ?? PUBLIC_TEXT_HOST_ALIASES[octet] ?? 'host:internal-node'
|
|
|
|
|
return PUBLIC_TEXT_HOST_ALIASES[octet] ?? 'host:internal-node'
|
|
|
|
|
})
|
|
|
|
|
return PUBLIC_TEXT_REPLACEMENTS.reduce((text, [pattern, replacement]) => text.replace(pattern, replacement), redactedLan)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function toneColor(tone: 'ok' | 'warn' | 'danger' | 'neutral') {
|
|
|
|
|
@@ -3871,165 +3902,6 @@ export function AutomationInventoryTab() {
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div style={{ padding: 12, border: '0.5px solid #b9d5ef', borderRadius: 7, background: '#f7fbff', display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0 }}>
|
|
|
|
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, flexWrap: 'wrap' }}>
|
|
|
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: 7, minWidth: 0 }}>
|
|
|
|
|
<Target size={14} style={{ color: '#2563eb' }} />
|
|
|
|
|
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 13, fontWeight: 700, color: '#141413' }}>
|
|
|
|
|
{t('criticReviewerResultCapture.title')}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<Chip
|
|
|
|
|
value={t('criticReviewerResultCapture.source', {
|
|
|
|
|
generated: formatDateTime(criticReviewerResultCapture.generated_at),
|
|
|
|
|
current: criticReviewerResultCapture.program_status.current_task_id,
|
|
|
|
|
next: criticReviewerResultCapture.program_status.next_task_id,
|
|
|
|
|
})}
|
|
|
|
|
muted
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(128px, 1fr))', gap: 10 }} className="automation-inventory-live-read-kpi-grid">
|
|
|
|
|
<MetricCard label={t('criticReviewerResultCapture.metrics.overall')} value={`${criticReviewerOverall}%`} tone="ok" icon={<Gauge size={16} />} />
|
|
|
|
|
<MetricCard label={t('criticReviewerResultCapture.metrics.scorecards')} value={criticReviewerScorecards} tone="warn" icon={<ShieldCheck size={16} />} />
|
|
|
|
|
<MetricCard label={t('criticReviewerResultCapture.metrics.captures')} value={criticReviewerCaptureContracts} tone="warn" icon={<FileText size={16} />} />
|
|
|
|
|
<MetricCard label={t('criticReviewerResultCapture.metrics.gates')} value={criticReviewerPromotionGates} tone="warn" icon={<Lock size={16} />} />
|
|
|
|
|
<MetricCard label={t('criticReviewerResultCapture.metrics.routes')} value={criticReviewerCandidateRoutes} tone="neutral" icon={<Route size={16} />} />
|
|
|
|
|
<MetricCard label={t('criticReviewerResultCapture.metrics.approvedGap')} value={criticReviewerApprovedGap} tone="danger" icon={<ShieldAlert size={16} />} />
|
|
|
|
|
<MetricCard label={t('criticReviewerResultCapture.metrics.failed')} value={criticReviewerFailedCandidates} tone="danger" icon={<AlertTriangle size={16} />} />
|
|
|
|
|
<MetricCard label={t('criticReviewerResultCapture.metrics.blockedGates')} value={criticReviewerBlockedGates} tone="danger" icon={<Lock size={16} />} />
|
|
|
|
|
<MetricCard label={t('criticReviewerResultCapture.metrics.ownerReviewGates')} value={criticReviewerOwnerReviewGates} tone="warn" icon={<Target size={16} />} />
|
|
|
|
|
<MetricCard label={t('criticReviewerResultCapture.metrics.criticScores')} value={criticReviewerRuntimeCriticScores} tone={criticReviewerRuntimeCriticScores === 0 ? 'warn' : 'danger'} icon={<ShieldCheck size={16} />} />
|
|
|
|
|
<MetricCard label={t('criticReviewerResultCapture.metrics.reviewerScores')} value={criticReviewerRuntimeReviewerScores} tone={criticReviewerRuntimeReviewerScores === 0 ? 'warn' : 'danger'} icon={<ShieldCheck size={16} />} />
|
|
|
|
|
<MetricCard label={t('criticReviewerResultCapture.metrics.captureWrites')} value={criticReviewerRuntimeCaptureWrites} tone={criticReviewerRuntimeCaptureWrites === 0 ? 'warn' : 'danger'} icon={<Database size={16} />} />
|
|
|
|
|
<MetricCard label={t('criticReviewerResultCapture.metrics.learningWrites')} value={criticReviewerLearningWrites} tone={criticReviewerLearningWrites === 0 ? 'warn' : 'danger'} icon={<Database size={16} />} />
|
|
|
|
|
<MetricCard label={t('criticReviewerResultCapture.metrics.trustWrites')} value={criticReviewerTrustWrites} tone={criticReviewerTrustWrites === 0 ? 'warn' : 'danger'} icon={<Database size={16} />} />
|
|
|
|
|
<MetricCard label={t('criticReviewerResultCapture.metrics.telegramSends')} value={criticReviewerTelegramSends} tone={criticReviewerTelegramSends === 0 ? 'warn' : 'danger'} icon={<BellRing size={16} />} />
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)', gap: 12 }} className="automation-inventory-live-read-grid">
|
|
|
|
|
<div style={{ padding: 11, border: '0.5px solid #b9d5ef', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
|
|
|
|
|
<SmallLabel>{t('criticReviewerResultCapture.truthTitle')}</SmallLabel>
|
|
|
|
|
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.5, overflowWrap: 'anywhere' }}>
|
|
|
|
|
{criticReviewerResultCapture.score_truth.truth_note}
|
|
|
|
|
</span>
|
|
|
|
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
|
|
|
|
<Chip value={t('criticReviewerResultCapture.flags.p2Loaded', { value: String(criticReviewerResultCapture.score_truth.p2_104_gap_loaded) })} />
|
|
|
|
|
<Chip value={t('criticReviewerResultCapture.flags.scoreRequired', { value: String(criticReviewerResultCapture.score_truth.critic_reviewer_score_required) })} />
|
|
|
|
|
<Chip value={t('criticReviewerResultCapture.flags.captureRequired', { value: String(criticReviewerResultCapture.score_truth.result_capture_required) })} />
|
|
|
|
|
<Chip value={t('criticReviewerResultCapture.flags.verifierRequired', { value: String(criticReviewerResultCapture.score_truth.post_write_verifier_required) })} />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div style={{ padding: 11, border: '0.5px solid #b9d5ef', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
|
|
|
|
|
<SmallLabel>{t('criticReviewerResultCapture.boundaryTitle')}</SmallLabel>
|
|
|
|
|
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.5, overflowWrap: 'anywhere' }}>
|
|
|
|
|
{t('criticReviewerResultCapture.boundarySummary', {
|
|
|
|
|
critic: criticReviewerRuntimeCriticScores,
|
|
|
|
|
reviewer: criticReviewerRuntimeReviewerScores,
|
|
|
|
|
capture: criticReviewerRuntimeCaptureWrites,
|
|
|
|
|
learning: criticReviewerLearningWrites,
|
|
|
|
|
trust: criticReviewerTrustWrites,
|
|
|
|
|
send: criticReviewerTelegramSends,
|
|
|
|
|
})}
|
|
|
|
|
</span>
|
|
|
|
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
|
|
|
|
<Chip value={t('criticReviewerResultCapture.flags.criticRuntime', { value: String(criticReviewerResultCapture.score_truth.runtime_critic_score_enabled) })} muted />
|
|
|
|
|
<Chip value={t('criticReviewerResultCapture.flags.reviewerRuntime', { value: String(criticReviewerResultCapture.score_truth.runtime_reviewer_score_enabled) })} muted />
|
|
|
|
|
<Chip value={t('criticReviewerResultCapture.flags.captureRuntime', { value: String(criticReviewerResultCapture.score_truth.runtime_result_capture_enabled) })} muted />
|
|
|
|
|
<Chip value={t('criticReviewerResultCapture.flags.send', { value: String(criticReviewerResultCapture.score_truth.telegram_send_enabled) })} muted />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
|
|
|
|
{visibleCriticReviewerScorecards.map(scorecard => (
|
|
|
|
|
<div key={scorecard.scorecard_id} style={{ padding: 10, border: '0.5px solid #b9d5ef', 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' }}>
|
|
|
|
|
{scorecard.display_name}
|
|
|
|
|
</span>
|
|
|
|
|
<Chip value={redisDryRunValueLabel('agents', scorecard.owner_agent)} muted />
|
|
|
|
|
</div>
|
|
|
|
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
|
|
|
|
<Chip value={t(`criticReviewerResultCapture.scoreStatuses.${scorecard.status}` as never)} muted={scorecard.status !== 'blocked_by_policy'} />
|
|
|
|
|
<Chip value={t(`criticReviewerResultCapture.roles.${scorecard.role}` as never)} muted />
|
|
|
|
|
<Chip value={t(`criticReviewerResultCapture.riskTiers.${scorecard.risk_tier}` as never)} muted />
|
|
|
|
|
<Chip value={t('criticReviewerResultCapture.labels.minimumScore', { value: scorecard.minimum_score })} muted />
|
|
|
|
|
<Chip value={t('criticReviewerResultCapture.labels.runtimeScore', { value: String(scorecard.runtime_score_enabled) })} muted />
|
|
|
|
|
</div>
|
|
|
|
|
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#b45309', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
|
|
|
|
{scorecard.failure_if_missing}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
|
|
|
|
{visibleResultCaptureContracts.map(contract => (
|
|
|
|
|
<div key={contract.contract_id} style={{ padding: 10, border: '0.5px solid #b9d5ef', 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' }}>
|
|
|
|
|
{contract.display_name}
|
|
|
|
|
</span>
|
|
|
|
|
<Chip value={redisDryRunValueLabel('agents', contract.owner_agent)} muted />
|
|
|
|
|
</div>
|
|
|
|
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
|
|
|
|
<Chip value={t(`criticReviewerResultCapture.captureStatuses.${contract.status}` as never)} muted={contract.status === 'ready'} />
|
|
|
|
|
<Chip value={contract.result_state} muted />
|
|
|
|
|
<Chip value={t('criticReviewerResultCapture.labels.count24h', { value: contract.count_24h })} muted />
|
|
|
|
|
<Chip value={t('criticReviewerResultCapture.labels.writeEnabled', { value: String(contract.write_enabled) })} muted />
|
|
|
|
|
</div>
|
|
|
|
|
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#b45309', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
|
|
|
|
{contract.blocker_summary}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(230px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
|
|
|
|
{visibleCriticReviewerPromotionGates.map(gate => (
|
|
|
|
|
<div key={gate.gate_id} style={{ padding: 10, border: '0.5px solid #b9d5ef', 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' }}>
|
|
|
|
|
{gate.display_name}
|
|
|
|
|
</span>
|
|
|
|
|
<Chip value={t(`criticReviewerResultCapture.gateStatuses.${gate.status}` as never)} muted={gate.status === 'ready'} />
|
|
|
|
|
</div>
|
|
|
|
|
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
|
|
|
|
{gate.required_before}
|
|
|
|
|
</span>
|
|
|
|
|
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#b45309', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
|
|
|
|
{gate.failure_if_missing}
|
|
|
|
|
</span>
|
|
|
|
|
<Chip value={t('criticReviewerResultCapture.labels.runtimeWrite', { value: String(gate.creates_runtime_write) })} muted />
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(230px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
|
|
|
|
{visibleCriticReviewerCandidateRoutes.map(route => (
|
|
|
|
|
<div key={route.route_id} style={{ padding: 10, border: '0.5px solid #b9d5ef', 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' }}>
|
|
|
|
|
{route.display_name}
|
|
|
|
|
</span>
|
|
|
|
|
<Chip value={redisDryRunValueLabel('agents', route.owner_agent)} muted />
|
|
|
|
|
</div>
|
|
|
|
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
|
|
|
|
<Chip value={t(`criticReviewerResultCapture.routeStatuses.${route.status}` as never)} muted={route.status !== 'blocked_by_policy'} />
|
|
|
|
|
<Chip value={t(`criticReviewerResultCapture.riskTiers.${route.risk_tier}` as never)} muted />
|
|
|
|
|
<Chip value={t('criticReviewerResultCapture.labels.candidateCount', { value: route.candidate_count_24h })} muted />
|
|
|
|
|
<Chip value={t('criticReviewerResultCapture.labels.writeEnabled', { value: String(route.write_enabled) })} muted />
|
|
|
|
|
</div>
|
|
|
|
|
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#2563eb', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
|
|
|
|
{route.next_gate}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div style={{ padding: 12, border: '0.5px solid #c8d5f2', borderRadius: 7, background: '#f8fbff', display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0 }}>
|
|
|
|
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, flexWrap: 'wrap' }}>
|
|
|
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: 7, minWidth: 0 }}>
|
|
|
|
|
@@ -7071,6 +6943,19 @@ export function AutomationInventoryTab() {
|
|
|
|
|
grid-template-columns: 1fr !important;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.automation-inventory-tab-root {
|
|
|
|
|
padding: 12px !important;
|
|
|
|
|
max-width: 100%;
|
|
|
|
|
overflow-x: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.automation-inventory-tab-root button,
|
|
|
|
|
.automation-inventory-tab-root [role='button'],
|
|
|
|
|
.automation-inventory-tab-root span,
|
|
|
|
|
.automation-inventory-tab-root div {
|
|
|
|
|
max-width: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.automation-inventory-live-read-card-grid > *,
|
|
|
|
|
.automation-inventory-live-read-kpi-grid > *,
|
|
|
|
|
.automation-inventory-service-health-notification-rule-grid > *,
|
|
|
|
|
|