@@ -350,22 +350,46 @@ function Format-AgentTelegramText {
$instruction = if ( $Data -and $Data . PSObject . Properties [ " instruction " ] ) { $Data . instruction } else { $null }
$exitCode = if ( $Data -and $Data . PSObject . Properties [ " exitCode " ] ) { $Data . exitCode } else { $null }
$evidencePath = if ( $Data -and $Data . PSObject . Properties [ " evidence " ] ) { $Data . evidence } else { $null }
$resultLabel = if ( $exitCode -eq 0 -or [ string ] ( Get-AgentObjectValue $Data " ok " " " ) -match " ^(?i:true|1) $ " ) { " 已完成 / resolved " } else { " 仍需處理 / failed " }
$actionText = switch ( $modeName ) {
" ProviderFreshness " { " 建立 provider freshness candidate, 要求 provider window、last seen、direct reference、verifier readback; 不切 provider。 " }
" BackupCheck " { " 讀回備份 freshness、status/log、snapshot metadata、cron contract; 不讀備份內容或 secrets。 " }
" Perf " { " 讀回主機 CPU/記憶體/磁碟;必要時只做 allowlisted 降載。 " }
" LoadShed " { " 執行 allowlisted 降載並做 post-apply verifier。 " }
" Recover " { " 依序檢查 VM、SSH、Harbor/K3s/public route, 必要時執行受控恢復。 " }
" StartVMs " { " 檢查並啟動 allowlisted VMware VM。 " }
" HarborRepair " { " 檢查 Harbor core/redis/registry, 必要時執行受控修復。 " }
" AwoooRepair " { " 檢查 AWOOOI/K3s pod、deployment、image pull 狀態,必要時受控修復。 " }
" SecurityTriage " { " 建立資安 triage candidate, 分類 blast radius、affected host/service、source log reference, 不任意 shell、不暴露 secrets。 " }
default { " 執行 allowlisted Agent99 mode 並寫入 evidence/KM。 " }
}
$lines + = " 事件 Event: Agent99 自動化結果 / automation result "
$lines + = " 模式 Mode: $modeName "
$lines + = " 來源 Source: $source "
$lines + = " 結果 Result: exitCode= $exitCode "
$lines + = " 結果 Result: $resultLabel , exitCode= $exitCode "
$lines + = " Agent99 動作 Action: $actionText "
if ( $Data -and $Data . PSObject . Properties [ " problem " ] ) {
$problem = $Data . problem
if ( $problem -and $problem . PSObject . Properties [ " occurrences " ] ) {
$lines + = " 問題計數 Problem count: occurrences= $( $problem . occurrences ) , resolved= $( $problem . resolved ) , failed= $( $problem . failed ) "
if ( $problem . PSObject . Properties [ " kmPath " ] ) {
$lines + = " KM: $( $problem . kmPath ) "
}
}
}
if ( $instruction -and $exitCode -ne 0 ) {
$lines + = " 失敗指令 Failure instruction: $instruction "
} elseif ( $instruction ) {
$lines + = " 處理摘要 Summary: $( Limit-AgentTextLine $instruction 130 ) "
}
if ( $evidencePath ) {
$lines + = " 證據 Evidence: $evidencePath "
}
if ( $exitCode -eq 0 ) {
$lines + = " 下一步 Next: 若相同問題再發生,依 problem count 追蹤重複率並回寫 PlayBook/KM。 "
} else {
$lines + = " 下一步 Next: 保留 failed queue/evidence, 升級到對應 playbook, 不做破壞性動作。 "
}
} elseif ( $EventType -eq " agent_control_tick " ) {
$dashboardPath = if ( $Data -and $Data . PSObject . Properties [ " dashboardPath " ] ) { $Data . dashboardPath } else { $null }
$processed = if ( $Data -and $Data . PSObject . Properties [ " processedCount " ] ) { $Data . processedCount } else { 0 }
@@ -428,11 +452,24 @@ function Get-AgentTelegramVisualPath {
$null
}
function Test-AgentSreOperatorResultAlertEnabled {
param ( [ object ] $Data )
if ( -not $Data ) { return $false }
$source = [ string ] ( Get-AgentObjectValue $Data " source " " " )
$alertId = [ string ] ( Get-AgentObjectValue $Data " alertId " " " )
$enabled = $true
if ( $Config . telegram -and $Config . telegram . PSObject . Properties [ " alertSreCommandResults " ] ) {
$enabled = Convert-AgentBool $Config . telegram . alertSreCommandResults
}
[ bool ] ( $enabled -and $source -eq " agent99-sre-alert-inbox " -and $alertId )
}
function New-AgentTelegramCardImage {
param (
[ string ] $Severity ,
[ string ] $EventType ,
[ string ] $Text
[ string ] $Text ,
[ object ] $Data = $null
)
$visualCardsEnabled = $true
@@ -440,7 +477,8 @@ function New-AgentTelegramCardImage {
$visualCardsEnabled = [ bool ] $Config . telegram . visualCardsEnabled
}
if ( -not $visualCardsEnabled ) { return $null }
if ( $Severity -notin @ ( " warning " , " critical " ) ) { return $null }
$forceVisual = [ bool ] ( $EventType -match " ^operator_command_ " -and ( Test-AgentSreOperatorResultAlertEnabled $Data ) )
if ( ( $Severity -notin @ ( " warning " , " critical " ) ) -and -not $forceVisual ) { return $null }
$cardDir = Join-Path $EvidenceDir " telegram-cards "
New-Item -ItemType Directory -Force -Path $cardDir | Out-Null
@@ -553,14 +591,51 @@ function Invoke-AgentTelegramCardSelfTest {
$text = Format-AgentTelegramText " warning " " performance_warning " " selftest visual card " $sample
$imagePath = New-AgentTelegramCardImage " warning " " performance_warning " $text
$ok = [ bool ] ( $imagePath -and ( Test-Path -LiteralPath $imagePath ) )
$operatorSample = [ pscustomobject ] @ {
id = " selftest-sre-result "
mode = " ProviderFreshness "
source = " agent99-sre-alert-inbox "
reason = " sre_alert "
instruction = " Provider freshness candidate required; alertId=selftest-provider; require providerWindow,lastSeen,directReference,verifierReadback; do not switch provider. "
alertId = " selftest-provider "
alertKind = " provider_freshness_signal "
alertSeverity = " warning "
alertService = " provider_freshness_signal "
ok = $true
exitCode = 0
evidence = $jsonPath
problem = [ pscustomobject ] @ {
key = " selftest-provider-freshness "
occurrences = 2
resolved = 2
failed = 0
kmPath = ( Join-Path $Config . agentRoot " playbooks\agent99-incident-km.md " )
}
}
$operatorText = Format-AgentTelegramText " info " " operator_command_result " " selftest SRE completion card " $operatorSample
$operatorImagePath = New-AgentTelegramCardImage " info " " operator_command_result " $operatorText $operatorSample
$operatorDecisionOk = Test-AgentSreOperatorResultAlertEnabled $operatorSample
$operatorTextOk = [ bool ] (
$operatorText -match " 已完成 / resolved " -and
$operatorText -match " Agent99 動作 Action " -and
$operatorText -match " 問題計數 Problem count " -and
$operatorText -match " KM: "
)
$operatorVisualOk = [ bool ] ( $operatorImagePath -and ( Test-Path -LiteralPath $operatorImagePath ) )
$ok = [ bool ] ( $ok -and $operatorTextOk -and $operatorVisualOk -and $operatorDecisionOk )
$result = [ pscustomobject ] @ {
timestamp = ( Get-Date -Format o )
ok = $ok
textPreview = @ ( $text -split " `n " | Select-Object -First 12 )
visualPath = $imagePath
visualExists = $ok
operatorTextPreview = @ ( $operatorText -split " `n " | Select-Object -First 14 )
operatorVisualPath = $operatorImagePath
operatorVisualExists = $operatorVisualOk
operatorTextOk = $operatorTextOk
operatorDecisionOk = $operatorDecisionOk
sentTelegram = $false
messageFormat = " incident_card_zh_tw_v3 "
messageFormat = " incident_card_zh_tw_v4 "
}
$selfTestPath = Join-Path $EvidenceDir " agent99-TelegramCardSelfTest- $stamp .json "
$result | ConvertTo-Json -Depth 6 | Set-Content -Path $selfTestPath -Encoding UTF8
@@ -584,7 +659,7 @@ function Invoke-AgentTelegramDeliverySelfTest {
ok = $sent
testId = $testId
sentTelegram = $sent
messageFormat = " incident_card_zh_tw_v3 "
messageFormat = " incident_card_zh_tw_v4 "
attempts = $script:TelegramAttempts
}
$selfTestPath = Join-Path $EvidenceDir " agent99-TelegramDeliverySelfTest- $stamp .json "
@@ -739,12 +814,12 @@ function Send-AgentTelegram {
$attempt . error = " telegram_disabled "
$script:TelegramAttempts + = $attempt
return
}
$text = Format-AgentTelegramText $Severity $EventType $Message $Data
$visualPath = Get-AgentTelegramVisualPath $Data
if ( -not $visualPath ) {
$visualPath = New-AgentTelegramCardImage $Severity $EventType $text
}
}
$text = Format-AgentTelegramText $Severity $EventType $Message $Data
$visualPath = Get-AgentTelegramVisualPath $Data
if ( -not $visualPath ) {
$visualPath = New-AgentTelegramCardImage $Severity $EventType $text $Data
}
$attempt . visualPath = $visualPath
if ( -not ( $token -and ( $chatId -or $chatIdOverride ) ) ) {
$relayResult = Send-AgentTelegramRelay $text $telegram . relay $chatIdOverride $visualPath
@@ -859,20 +934,28 @@ function Record-AgentEvent {
$operatorOk = $false
$operatorMode = " "
$operatorId = " "
$operatorSource = " "
$operatorAlertId = " "
$operatorOkValue = $null
$operatorExitCode = $null
if ( $Data -is [ System.Collections.IDictionary ] ) {
if ( $Data . Contains ( " mode " ) ) { $operatorMode = [ string ] $Data [ " mode " ] }
if ( $Data . Contains ( " id " ) ) { $operatorId = [ string ] $Data [ " id " ] }
if ( $Data . Contains ( " source " ) ) { $operatorSource = [ string ] $Data [ " source " ] }
if ( $Data . Contains ( " alertId " ) ) { $operatorAlertId = [ string ] $Data [ " alertId " ] }
if ( $Data . Contains ( " ok " ) ) { $operatorOkValue = $Data [ " ok " ] }
if ( $Data . Contains ( " exitCode " ) ) { $operatorExitCode = $Data [ " exitCode " ] }
} else {
$modeProp = $Data . PSObject . Properties . Match ( " mode " ) | Select-Object -First 1
$idProp = $Data . PSObject . Properties . Match ( " id " ) | Select-Object -First 1
$sourceProp = $Data . PSObject . Properties . Match ( " source " ) | Select-Object -First 1
$alertIdProp = $Data . PSObject . Properties . Match ( " alertId " ) | Select-Object -First 1
$okProp = $Data . PSObject . Properties . Match ( " ok " ) | Select-Object -First 1
$exitCodeProp = $Data . PSObject . Properties . Match ( " exitCode " ) | Select-Object -First 1
if ( $modeProp ) { $operatorMode = [ string ] $modeProp . Value }
if ( $idProp ) { $operatorId = [ string ] $idProp . Value }
if ( $sourceProp ) { $operatorSource = [ string ] $sourceProp . Value }
if ( $alertIdProp ) { $operatorAlertId = [ string ] $alertIdProp . Value }
if ( $okProp ) { $operatorOkValue = $okProp . Value }
if ( $exitCodeProp ) { $operatorExitCode = $exitCodeProp . Value }
}
@@ -883,9 +966,12 @@ function Record-AgentEvent {
if ( $Config . telegram -and $Config . telegram . PSObject . Properties [ " alertSuccessfulOperatorCommands " ] ) {
$alertSuccessfulOperatorCommands = [ bool ] $Config . telegram . alertSuccessfulOperatorCommands
}
if ( $operatorOk -and -not $alertSuccessfulOperatorCommands ) {
$operatorIsSreAlertResult = Test-AgentSreOperatorResultAlertEnabled $Data
if ( $operatorOk -and -not $alertSuccessfulOperatorCommands -and -not $operatorIsSreAlertResult ) {
Write-AgentLog " telegram_operator_success_suppressed type= $EventType mode= $operatorMode id= $operatorId "
$operatorCommandAlert = $false
} elseif ( $operatorOk -and $operatorIsSreAlertResult ) {
Write-AgentLog " telegram_sre_operator_success_enabled type= $EventType mode= $operatorMode id= $operatorId alertId= $operatorAlertId "
}
}
$shouldAlert = ( $Severity -in @ ( " warning " , " critical " ) ) -or $operatorCommandAlert -or ( $Alert -and $Severity -ne " info " ) -or ( $alertAll -and ( $Severity -ne " info " -or $alertInfo ) )