72 lines
3.6 KiB
Swift
72 lines
3.6 KiB
Swift
// SPDX-FileCopyrightText: 2026 Kaede Akino
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
import AgentKit
|
|
import Foundation
|
|
import TermindApplication
|
|
|
|
extension AppStrings {
|
|
public nonisolated enum Notifications {
|
|
public static var title: LocalizedStringResource { "Notifications" }
|
|
public static var enabled: LocalizedStringResource { "Enabled" }
|
|
public static var allow: LocalizedStringResource { "Allow Notifications" }
|
|
public static var delivery: LocalizedStringResource { "Notification Type" }
|
|
public static var system: LocalizedStringResource { "System Notifications" }
|
|
public static var bell: LocalizedStringResource { "Bell" }
|
|
public static var unfocused: LocalizedStringResource { "Unfocused" }
|
|
public static var markRead: LocalizedStringResource { "Mark as Read" }
|
|
public static var markUnread: LocalizedStringResource { "Mark as Unread" }
|
|
public static func transfersCompleted(succeeded: Int, failed: Int) -> LocalizedStringResource {
|
|
if failed == 0 {
|
|
return succeeded == 1 ? "The transfer is complete." : "All \(succeeded) transfers are complete."
|
|
}
|
|
if succeeded == 0 {
|
|
return failed == 1 ? "The transfer failed." : "All \(failed) transfers failed."
|
|
}
|
|
return "Transfers finished: \(succeeded) completed, \(failed) failed."
|
|
}
|
|
public static func unread(_ count: Int) -> LocalizedStringResource { "Unread notifications: \(count)" }
|
|
|
|
public static func body(_ kind: AssistantNotificationKind) -> LocalizedStringResource {
|
|
switch kind {
|
|
case .mcpAuthorization: "Please authorize the MCP connection to continue."
|
|
case .completed: "The task is complete."
|
|
case .failed: "The task failed. Open the conversation for details."
|
|
case .questions: "Please provide some information to continue."
|
|
case .secret: "Please enter your credentials to continue."
|
|
case .approval: "An action needs your approval."
|
|
case .authentication: "Please complete SSH authentication to continue."
|
|
case .passphrase: "Please enter your SSH key passphrase."
|
|
case .hostKey: "Please confirm this host's key to continue."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum AssistantNotificationContent {
|
|
public static func make(
|
|
_ conversation: ConversationModel, kind: AssistantNotificationKind, runID: UUID? = nil
|
|
) -> (title: String, body: String) {
|
|
let title = conversation.derivedTitle
|
|
let sanitized = title.unicodeScalars.map {
|
|
CharacterSet.controlCharacters.contains($0) ? " " : String($0)
|
|
}.joined()
|
|
var body = String(localized: AppStrings.Notifications.body(kind))
|
|
if kind == .completed, let runID,
|
|
let reply = conversation.transcript.last(where: {
|
|
$0.role == .assistant && $0.toolCalls.isEmpty && conversation.messageRunIDs[$0.id] == runID
|
|
&& !$0.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
|
})
|
|
{
|
|
body = AgentSensitiveDataRedactor.visibleText(
|
|
reply.text.trimmingCharacters(in: .whitespacesAndNewlines), maximumCharacters: 2_000)
|
|
} else if kind == .failed, let runID,
|
|
let reason = conversation.runSummaries[runID]?.failure?.trimmingCharacters(in: .whitespacesAndNewlines),
|
|
!reason.isEmpty
|
|
{
|
|
body = AgentSensitiveDataRedactor.visibleText(reason, maximumCharacters: 500)
|
|
}
|
|
return (String(sanitized.prefix(160)), body)
|
|
}
|
|
}
|